diff options
Diffstat (limited to '')
51 files changed, 9203 insertions, 0 deletions
diff --git a/xbmc/utils/test/CMakeLists.txt b/xbmc/utils/test/CMakeLists.txt new file mode 100644 index 0000000..a5ba095 --- /dev/null +++ b/xbmc/utils/test/CMakeLists.txt @@ -0,0 +1,51 @@ +set(SOURCES TestAlarmClock.cpp + TestAliasShortcutUtils.cpp + TestArchive.cpp + TestBase64.cpp + TestBitstreamStats.cpp + TestCharsetConverter.cpp + TestCPUInfo.cpp + TestComponentContainer.cpp + TestCrc32.cpp + TestDatabaseUtils.cpp + TestDigest.cpp + TestEndianSwap.cpp + TestExecString.cpp + TestFileOperationJob.cpp + TestFileUtils.cpp + TestGlobalsHandling.cpp + TestHTMLUtil.cpp + TestHttpHeader.cpp + TestHttpParser.cpp + TestHttpRangeUtils.cpp + TestHttpResponse.cpp + TestJobManager.cpp + TestJSONVariantParser.cpp + TestJSONVariantWriter.cpp + TestLabelFormatter.cpp + TestLangCodeExpander.cpp + TestLocale.cpp + Testlog.cpp + TestMathUtils.cpp + TestMime.cpp + TestPOUtils.cpp + TestRegExp.cpp + Testrfft.cpp + TestRingBuffer.cpp + TestScraperParser.cpp + TestScraperUrl.cpp + TestSortUtils.cpp + TestStopwatch.cpp + TestStreamDetails.cpp + TestStreamUtils.cpp + TestStringUtils.cpp + TestSystemInfo.cpp + TestURIUtils.cpp + TestUrlOptions.cpp + TestVariant.cpp + TestXBMCTinyXML.cpp + TestXMLUtils.cpp) + +set(HEADERS TestGlobalsHandlingPattern1.h) + +core_add_test_library(utils_test) diff --git a/xbmc/utils/test/CXBMCTinyXML-test.xml b/xbmc/utils/test/CXBMCTinyXML-test.xml new file mode 100644 index 0000000..9444dc8 --- /dev/null +++ b/xbmc/utils/test/CXBMCTinyXML-test.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<details> + <url function="ParseTMDBRating" cache="tmdb-en-12244.json"> + http://api.themoviedb.org/3/movie/12244?api_key=57983e31fb435df4df77afb854740ea9&language=en??? + </url> +</details> diff --git a/xbmc/utils/test/TestAlarmClock.cpp b/xbmc/utils/test/TestAlarmClock.cpp new file mode 100644 index 0000000..75ea84a --- /dev/null +++ b/xbmc/utils/test/TestAlarmClock.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/AlarmClock.h" + +#include <gtest/gtest.h> + +TEST(TestAlarmClock, General) +{ + CAlarmClock a; + EXPECT_FALSE(a.IsRunning()); + EXPECT_FALSE(a.HasAlarm("test")); + a.Start("test", 100.f, "test"); + EXPECT_TRUE(a.IsRunning()); + EXPECT_TRUE(a.HasAlarm("test")); + EXPECT_FALSE(a.HasAlarm("test2")); + EXPECT_NE(0.f, a.GetRemaining("test")); + EXPECT_EQ(0.f, a.GetRemaining("test2")); + a.Stop("test"); +} diff --git a/xbmc/utils/test/TestAliasShortcutUtils.cpp b/xbmc/utils/test/TestAliasShortcutUtils.cpp new file mode 100644 index 0000000..d36fd41 --- /dev/null +++ b/xbmc/utils/test/TestAliasShortcutUtils.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/AliasShortcutUtils.h" +#include "filesystem/File.h" +#include "test/TestUtils.h" + +#if defined(TARGET_DARWIN_OSX) +#include "platform/darwin/DarwinUtils.h" +#endif +#include <gtest/gtest.h> + +TEST(TestAliasShortcutUtils, IsAliasShortcut) +{ + XFILE::CFile *tmpFile = XBMC_CREATETEMPFILE("noaliastest"); + std::string noalias = XBMC_TEMPFILEPATH(tmpFile); + +#if defined(TARGET_DARWIN_OSX) + XFILE::CFile *aliasDestFile = XBMC_CREATETEMPFILE("aliastest"); + std::string alias = XBMC_TEMPFILEPATH(aliasDestFile); + + //we only need the path here so delete the alias file + //which will be recreated as shortcut later: + XBMC_DELETETEMPFILE(aliasDestFile); + + // create alias from a pointing to /Volumes + CDarwinUtils::CreateAliasShortcut(alias, "/Volumes"); + EXPECT_TRUE(IsAliasShortcut(alias, true)); + XFILE::CFile::Delete(alias); + + // volumes is not a shortcut but a dir + EXPECT_FALSE(IsAliasShortcut("/Volumes", true)); +#endif + + // a regular file is not a shortcut + EXPECT_FALSE(IsAliasShortcut(noalias, false)); + XBMC_DELETETEMPFILE(tmpFile); + + // empty string is not an alias + std::string emptyString; + EXPECT_FALSE(IsAliasShortcut(emptyString, false)); + + // non-existent file is no alias + std::string nonExistingFile="/IDontExistsNormally/somefile.txt"; + EXPECT_FALSE(IsAliasShortcut(nonExistingFile, false)); +} + +TEST(TestAliasShortcutUtils, TranslateAliasShortcut) +{ + XFILE::CFile *tmpFile = XBMC_CREATETEMPFILE("noaliastest"); + std::string noalias = XBMC_TEMPFILEPATH(tmpFile); + std::string noaliastemp = noalias; + +#if defined(TARGET_DARWIN_OSX) + XFILE::CFile *aliasDestFile = XBMC_CREATETEMPFILE("aliastest"); + std::string alias = XBMC_TEMPFILEPATH(aliasDestFile); + + //we only need the path here so delete the alias file + //which will be recreated as shortcut later: + XBMC_DELETETEMPFILE(aliasDestFile); + + // create alias from a pointing to /Volumes + CDarwinUtils::CreateAliasShortcut(alias, "/Volumes"); + + // resolve the shortcut + TranslateAliasShortcut(alias); + EXPECT_STREQ("/Volumes", alias.c_str()); + XFILE::CFile::Delete(alias); +#endif + + // translating a non-shortcut url should result in no change... + TranslateAliasShortcut(noaliastemp); + EXPECT_STREQ(noaliastemp.c_str(), noalias.c_str()); + XBMC_DELETETEMPFILE(tmpFile); + + //translate empty should stay empty + std::string emptyString; + TranslateAliasShortcut(emptyString); + EXPECT_STREQ("", emptyString.c_str()); + + // translate non-existent file should result in no change... + std::string nonExistingFile="/IDontExistsNormally/somefile.txt"; + std::string resolvedNonExistingFile=nonExistingFile; + TranslateAliasShortcut(resolvedNonExistingFile); + EXPECT_STREQ(resolvedNonExistingFile.c_str(), nonExistingFile.c_str()); +} diff --git a/xbmc/utils/test/TestArchive.cpp b/xbmc/utils/test/TestArchive.cpp new file mode 100644 index 0000000..90628ea --- /dev/null +++ b/xbmc/utils/test/TestArchive.cpp @@ -0,0 +1,411 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#if defined(TARGET_WINDOWS) +# include <windows.h> +#endif + +#include "filesystem/File.h" +#include "test/TestUtils.h" +#include "utils/Archive.h" +#include "utils/Variant.h" +#include "utils/XTimeUtils.h" + +#include <gtest/gtest.h> + +class TestArchive : public testing::Test +{ +protected: + TestArchive() + { + file = XBMC_CREATETEMPFILE(".ar"); + } + ~TestArchive() override + { + EXPECT_TRUE(XBMC_DELETETEMPFILE(file)); + } + XFILE::CFile *file; +}; + +TEST_F(TestArchive, IsStoring) +{ + ASSERT_NE(nullptr, file); + CArchive arstore(file, CArchive::store); + EXPECT_TRUE(arstore.IsStoring()); + EXPECT_FALSE(arstore.IsLoading()); + arstore.Close(); +} + +TEST_F(TestArchive, IsLoading) +{ + ASSERT_NE(nullptr, file); + CArchive arload(file, CArchive::load); + EXPECT_TRUE(arload.IsLoading()); + EXPECT_FALSE(arload.IsStoring()); + arload.Close(); +} + +TEST_F(TestArchive, FloatArchive) +{ + ASSERT_NE(nullptr, file); + float float_ref = 1, float_var = 0; + + CArchive arstore(file, CArchive::store); + arstore << float_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> float_var; + arload.Close(); + + EXPECT_EQ(float_ref, float_var); +} + +TEST_F(TestArchive, DoubleArchive) +{ + ASSERT_NE(nullptr, file); + double double_ref = 2, double_var = 0; + + CArchive arstore(file, CArchive::store); + arstore << double_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> double_var; + arload.Close(); + + EXPECT_EQ(double_ref, double_var); +} + +TEST_F(TestArchive, IntegerArchive) +{ + ASSERT_NE(nullptr, file); + int int_ref = 3, int_var = 0; + + CArchive arstore(file, CArchive::store); + arstore << int_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> int_var; + arload.Close(); + + EXPECT_EQ(int_ref, int_var); +} + +TEST_F(TestArchive, UnsignedIntegerArchive) +{ + ASSERT_NE(nullptr, file); + unsigned int unsigned_int_ref = 4, unsigned_int_var = 0; + + CArchive arstore(file, CArchive::store); + arstore << unsigned_int_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> unsigned_int_var; + arload.Close(); + + EXPECT_EQ(unsigned_int_ref, unsigned_int_var); +} + +TEST_F(TestArchive, Int64tArchive) +{ + ASSERT_NE(nullptr, file); + int64_t int64_t_ref = 5, int64_t_var = 0; + + CArchive arstore(file, CArchive::store); + arstore << int64_t_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> int64_t_var; + arload.Close(); + + EXPECT_EQ(int64_t_ref, int64_t_var); +} + +TEST_F(TestArchive, UInt64tArchive) +{ + ASSERT_NE(nullptr, file); + uint64_t uint64_t_ref = 6, uint64_t_var = 0; + + CArchive arstore(file, CArchive::store); + arstore << uint64_t_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> uint64_t_var; + arload.Close(); + + EXPECT_EQ(uint64_t_ref, uint64_t_var); +} + +TEST_F(TestArchive, BoolArchive) +{ + ASSERT_NE(nullptr, file); + bool bool_ref = true, bool_var = false; + + CArchive arstore(file, CArchive::store); + arstore << bool_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> bool_var; + arload.Close(); + + EXPECT_EQ(bool_ref, bool_var); +} + +TEST_F(TestArchive, CharArchive) +{ + ASSERT_NE(nullptr, file); + char char_ref = 'A', char_var = '\0'; + + CArchive arstore(file, CArchive::store); + arstore << char_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> char_var; + arload.Close(); + + EXPECT_EQ(char_ref, char_var); +} + +TEST_F(TestArchive, WStringArchive) +{ + ASSERT_NE(nullptr, file); + std::wstring wstring_ref = L"test wstring", wstring_var; + + CArchive arstore(file, CArchive::store); + arstore << wstring_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> wstring_var; + arload.Close(); + + EXPECT_STREQ(wstring_ref.c_str(), wstring_var.c_str()); +} + +TEST_F(TestArchive, StringArchive) +{ + ASSERT_NE(nullptr, file); + std::string string_ref = "test string", string_var; + + CArchive arstore(file, CArchive::store); + arstore << string_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> string_var; + arload.Close(); + + EXPECT_STREQ(string_ref.c_str(), string_var.c_str()); +} + +TEST_F(TestArchive, SystemTimeArchive) +{ + ASSERT_NE(nullptr, file); + KODI::TIME::SystemTime SystemTime_ref = {1, 2, 3, 4, 5, 6, 7, 8}; + KODI::TIME::SystemTime SystemTime_var = {0, 0, 0, 0, 0, 0, 0, 0}; + + CArchive arstore(file, CArchive::store); + arstore << SystemTime_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> SystemTime_var; + arload.Close(); + + EXPECT_TRUE(!memcmp(&SystemTime_ref, &SystemTime_var, sizeof(KODI::TIME::SystemTime))); +} + +TEST_F(TestArchive, CVariantArchive) +{ + ASSERT_NE(nullptr, file); + CVariant CVariant_ref((int)1), CVariant_var; + + CArchive arstore(file, CArchive::store); + arstore << CVariant_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> CVariant_var; + arload.Close(); + + EXPECT_TRUE(CVariant_var.isInteger()); + EXPECT_EQ(1, CVariant_var.asInteger()); +} + +TEST_F(TestArchive, CVariantArchiveString) +{ + ASSERT_NE(nullptr, file); + CVariant CVariant_ref("teststring"), CVariant_var; + + CArchive arstore(file, CArchive::store); + arstore << CVariant_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> CVariant_var; + arload.Close(); + + EXPECT_TRUE(CVariant_var.isString()); + EXPECT_STREQ("teststring", CVariant_var.asString().c_str()); +} + +TEST_F(TestArchive, StringVectorArchive) +{ + ASSERT_NE(nullptr, file); + std::vector<std::string> strArray_ref, strArray_var; + strArray_ref.emplace_back("test strArray_ref 0"); + strArray_ref.emplace_back("test strArray_ref 1"); + strArray_ref.emplace_back("test strArray_ref 2"); + strArray_ref.emplace_back("test strArray_ref 3"); + + CArchive arstore(file, CArchive::store); + arstore << strArray_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> strArray_var; + arload.Close(); + + EXPECT_STREQ("test strArray_ref 0", strArray_var.at(0).c_str()); + EXPECT_STREQ("test strArray_ref 1", strArray_var.at(1).c_str()); + EXPECT_STREQ("test strArray_ref 2", strArray_var.at(2).c_str()); + EXPECT_STREQ("test strArray_ref 3", strArray_var.at(3).c_str()); +} + +TEST_F(TestArchive, IntegerVectorArchive) +{ + ASSERT_NE(nullptr, file); + std::vector<int> iArray_ref, iArray_var; + iArray_ref.push_back(0); + iArray_ref.push_back(1); + iArray_ref.push_back(2); + iArray_ref.push_back(3); + + CArchive arstore(file, CArchive::store); + arstore << iArray_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + arload >> iArray_var; + arload.Close(); + + EXPECT_EQ(0, iArray_var.at(0)); + EXPECT_EQ(1, iArray_var.at(1)); + EXPECT_EQ(2, iArray_var.at(2)); + EXPECT_EQ(3, iArray_var.at(3)); +} + +TEST_F(TestArchive, MultiTypeArchive) +{ + ASSERT_NE(nullptr, file); + float float_ref = 1, float_var = 0; + double double_ref = 2, double_var = 0; + int int_ref = 3, int_var = 0; + unsigned int unsigned_int_ref = 4, unsigned_int_var = 0; + int64_t int64_t_ref = 5, int64_t_var = 0; + uint64_t uint64_t_ref = 6, uint64_t_var = 0; + bool bool_ref = true, bool_var = false; + char char_ref = 'A', char_var = '\0'; + std::string string_ref = "test string", string_var; + std::wstring wstring_ref = L"test wstring", wstring_var; + KODI::TIME::SystemTime SystemTime_ref = {1, 2, 3, 4, 5, 6, 7, 8}; + KODI::TIME::SystemTime SystemTime_var = {0, 0, 0, 0, 0, 0, 0, 0}; + CVariant CVariant_ref((int)1), CVariant_var; + std::vector<std::string> strArray_ref, strArray_var; + strArray_ref.emplace_back("test strArray_ref 0"); + strArray_ref.emplace_back("test strArray_ref 1"); + strArray_ref.emplace_back("test strArray_ref 2"); + strArray_ref.emplace_back("test strArray_ref 3"); + std::vector<int> iArray_ref, iArray_var; + iArray_ref.push_back(0); + iArray_ref.push_back(1); + iArray_ref.push_back(2); + iArray_ref.push_back(3); + + CArchive arstore(file, CArchive::store); + EXPECT_TRUE(arstore.IsStoring()); + EXPECT_FALSE(arstore.IsLoading()); + arstore << float_ref; + arstore << double_ref; + arstore << int_ref; + arstore << unsigned_int_ref; + arstore << int64_t_ref; + arstore << uint64_t_ref; + arstore << bool_ref; + arstore << char_ref; + arstore << string_ref; + arstore << wstring_ref; + arstore << SystemTime_ref; + arstore << CVariant_ref; + arstore << strArray_ref; + arstore << iArray_ref; + arstore.Close(); + + ASSERT_EQ(0, file->Seek(0, SEEK_SET)); + CArchive arload(file, CArchive::load); + EXPECT_TRUE(arload.IsLoading()); + EXPECT_FALSE(arload.IsStoring()); + arload >> float_var; + arload >> double_var; + arload >> int_var; + arload >> unsigned_int_var; + arload >> int64_t_var; + arload >> uint64_t_var; + arload >> bool_var; + arload >> char_var; + arload >> string_var; + arload >> wstring_var; + arload >> SystemTime_var; + arload >> CVariant_var; + arload >> strArray_var; + arload >> iArray_var; + arload.Close(); + + EXPECT_EQ(float_ref, float_var); + EXPECT_EQ(double_ref, double_var); + EXPECT_EQ(int_ref, int_var); + EXPECT_EQ(unsigned_int_ref, unsigned_int_var); + EXPECT_EQ(int64_t_ref, int64_t_var); + EXPECT_EQ(uint64_t_ref, uint64_t_var); + EXPECT_EQ(bool_ref, bool_var); + EXPECT_EQ(char_ref, char_var); + EXPECT_STREQ(string_ref.c_str(), string_var.c_str()); + EXPECT_STREQ(wstring_ref.c_str(), wstring_var.c_str()); + EXPECT_TRUE(!memcmp(&SystemTime_ref, &SystemTime_var, sizeof(KODI::TIME::SystemTime))); + EXPECT_TRUE(CVariant_var.isInteger()); + EXPECT_STREQ("test strArray_ref 0", strArray_var.at(0).c_str()); + EXPECT_STREQ("test strArray_ref 1", strArray_var.at(1).c_str()); + EXPECT_STREQ("test strArray_ref 2", strArray_var.at(2).c_str()); + EXPECT_STREQ("test strArray_ref 3", strArray_var.at(3).c_str()); + EXPECT_EQ(0, iArray_var.at(0)); + EXPECT_EQ(1, iArray_var.at(1)); + EXPECT_EQ(2, iArray_var.at(2)); + EXPECT_EQ(3, iArray_var.at(3)); +} diff --git a/xbmc/utils/test/TestBase64.cpp b/xbmc/utils/test/TestBase64.cpp new file mode 100644 index 0000000..8416378 --- /dev/null +++ b/xbmc/utils/test/TestBase64.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/Base64.h" + +#include <gtest/gtest.h> + +static const char refdata[] = "\x01\x02\x03\x04\x05\x06\x07\x08" + "\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" + "\x11\x12\x13\x14\x15\x16\x17\x18" + "\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20" + "\x21\x22\x23\x24\x25\x26\x27\x28" + "\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30"; + +static const char refbase64data[] = "AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcY" + "GRobHB0eHyAhIiMkJSYnKCkqKywtLi8w"; + +TEST(TestBase64, Encode_1) +{ + std::string a; + Base64::Encode(refdata, sizeof(refdata) - 1, a); + EXPECT_STREQ(refbase64data, a.c_str()); +} + +TEST(TestBase64, Encode_2) +{ + std::string a; + a = Base64::Encode(refdata, sizeof(refdata) - 1); + EXPECT_STREQ(refbase64data, a.c_str()); +} + +TEST(TestBase64, Encode_3) +{ + std::string a; + Base64::Encode(refdata, a); + EXPECT_STREQ(refbase64data, a.c_str()); +} + +TEST(TestBase64, Encode_4) +{ + std::string a; + a = Base64::Encode(refdata); + EXPECT_STREQ(refbase64data, a.c_str()); +} + +TEST(TestBase64, Decode_1) +{ + std::string a; + Base64::Decode(refbase64data, sizeof(refbase64data) - 1, a); + EXPECT_STREQ(refdata, a.c_str()); +} + +TEST(TestBase64, Decode_2) +{ + std::string a; + a = Base64::Decode(refbase64data, sizeof(refbase64data) - 1); + EXPECT_STREQ(refdata, a.c_str()); +} + +TEST(TestBase64, Decode_3) +{ + std::string a; + Base64::Decode(refbase64data, a); + EXPECT_STREQ(refdata, a.c_str()); +} + +TEST(TestBase64, Decode_4) +{ + std::string a; + a = Base64::Decode(refbase64data); + EXPECT_STREQ(refdata, a.c_str()); +} diff --git a/xbmc/utils/test/TestBitstreamStats.cpp b/xbmc/utils/test/TestBitstreamStats.cpp new file mode 100644 index 0000000..200a633 --- /dev/null +++ b/xbmc/utils/test/TestBitstreamStats.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "threads/Thread.h" +#include "utils/BitstreamStats.h" + +#include <gtest/gtest.h> + +using namespace std::chrono_literals; + +#define BITS (256 * 8) +#define BYTES (256) + +class CTestBitstreamStatsThread : public CThread +{ +public: + CTestBitstreamStatsThread() : + CThread("TestBitstreamStats"){} + +}; + +TEST(TestBitstreamStats, General) +{ + int i; + BitstreamStats a; + CTestBitstreamStatsThread t; + + i = 0; + a.Start(); + EXPECT_EQ(0.0, a.GetBitrate()); + EXPECT_EQ(0.0, a.GetMaxBitrate()); + EXPECT_EQ(-1.0, a.GetMinBitrate()); + while (i <= BITS) + { + a.AddSampleBits(1); + i++; + t.Sleep(1ms); + } + a.CalculateBitrate(); + EXPECT_GT(a.GetBitrate(), 0.0); + EXPECT_GT(a.GetMaxBitrate(), 0.0); + EXPECT_GT(a.GetMinBitrate(), 0.0); + + i = 0; + while (i <= BYTES) + { + a.AddSampleBytes(1); + t.Sleep(2ms); + i++; + } + a.CalculateBitrate(); + EXPECT_GT(a.GetBitrate(), 0.0); + EXPECT_GT(a.GetMaxBitrate(), 0.0); + EXPECT_LE(a.GetMinBitrate(), a.GetMaxBitrate()); +} diff --git a/xbmc/utils/test/TestCPUInfo.cpp b/xbmc/utils/test/TestCPUInfo.cpp new file mode 100644 index 0000000..bd9572a --- /dev/null +++ b/xbmc/utils/test/TestCPUInfo.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#if defined(TARGET_WINDOWS) +# include <windows.h> +#endif + +#include "ServiceBroker.h" +#include "settings/AdvancedSettings.h" +#include "settings/SettingsComponent.h" +#include "utils/CPUInfo.h" +#include "utils/Temperature.h" +#include "utils/XTimeUtils.h" + +#include <gtest/gtest.h> + +struct TestCPUInfo : public ::testing::Test +{ + TestCPUInfo() { CServiceBroker::RegisterCPUInfo(CCPUInfo::GetCPUInfo()); } + + ~TestCPUInfo() { CServiceBroker::UnregisterCPUInfo(); } +}; + +TEST_F(TestCPUInfo, GetUsedPercentage) +{ + EXPECT_GE(CServiceBroker::GetCPUInfo()->GetUsedPercentage(), 0); +} + +TEST_F(TestCPUInfo, GetCPUCount) +{ + EXPECT_GT(CServiceBroker::GetCPUInfo()->GetCPUCount(), 0); +} + +TEST_F(TestCPUInfo, GetCPUFrequency) +{ + EXPECT_GE(CServiceBroker::GetCPUInfo()->GetCPUFrequency(), 0.f); +} + +#if defined(TARGET_WINDOWS) +TEST_F(TestCPUInfo, DISABLED_GetTemperature) +#else +TEST_F(TestCPUInfo, GetTemperature) +#endif +{ + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_cpuTempCmd = "echo '50 c'"; + CTemperature t; + EXPECT_TRUE(CServiceBroker::GetCPUInfo()->GetTemperature(t)); + EXPECT_TRUE(t.IsValid()); +} + +TEST_F(TestCPUInfo, CoreInfo) +{ + ASSERT_TRUE(CServiceBroker::GetCPUInfo()->HasCoreId(0)); + const CoreInfo c = CServiceBroker::GetCPUInfo()->GetCoreInfo(0); + EXPECT_TRUE(c.m_id == 0); +} + +TEST_F(TestCPUInfo, GetCoresUsageString) +{ + EXPECT_STRNE("", CServiceBroker::GetCPUInfo()->GetCoresUsageString().c_str()); +} + +TEST_F(TestCPUInfo, GetCPUFeatures) +{ + unsigned int a = CServiceBroker::GetCPUInfo()->GetCPUFeatures(); + (void)a; +} diff --git a/xbmc/utils/test/TestCharsetConverter.cpp b/xbmc/utils/test/TestCharsetConverter.cpp new file mode 100644 index 0000000..f8736b7 --- /dev/null +++ b/xbmc/utils/test/TestCharsetConverter.cpp @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "ServiceBroker.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "utils/CharsetConverter.h" +#include "utils/Utf8Utils.h" + +#include <gtest/gtest.h> + +#if 0 +static const uint16_t refutf16LE1[] = { 0xff54, 0xff45, 0xff53, 0xff54, + 0xff3f, 0xff55, 0xff54, 0xff46, + 0xff11, 0xff16, 0xff2c, 0xff25, + 0xff54, 0xff4f, 0xff57, 0x0 }; + +static const uint16_t refutf16LE2[] = { 0xff54, 0xff45, 0xff53, 0xff54, + 0xff3f, 0xff55, 0xff54, 0xff46, + 0xff18, 0xff34, 0xff4f, 0xff1a, + 0xff3f, 0xff43, 0xff48, 0xff41, + 0xff52, 0xff53, 0xff45, 0xff54, + 0xff3f, 0xff35, 0xff34, 0xff26, + 0xff0d, 0xff11, 0xff16, 0xff2c, + 0xff25, 0xff0c, 0xff3f, 0xff23, + 0xff33, 0xff54, 0xff44, 0xff33, + 0xff54, 0xff52, 0xff49, 0xff4e, + 0xff47, 0xff11, 0xff16, 0x0 }; +#endif + +static const char refutf16LE3[] = "T\377E\377S\377T\377?\377S\377T\377" + "R\377I\377N\377G\377#\377H\377A\377" + "R\377S\377E\377T\377\064\377O\377\065" + "\377T\377F\377\030\377"; + +#if 0 +static const uint16_t refutf16LE4[] = { 0xff54, 0xff45, 0xff53, 0xff54, + 0xff3f, 0xff55, 0xff54, 0xff46, + 0xff11, 0xff16, 0xff2c, 0xff25, + 0xff54, 0xff4f, 0xff35, 0xff34, + 0xff26, 0xff18, 0x0 }; + +static const uint32_t refutf32LE1[] = { 0xff54, 0xff45, 0xff53, 0xff54, + 0xff3f, 0xff55, 0xff54, 0xff46, + 0xff18, 0xff34, 0xff4f, 0xff1a, + 0xff3f, 0xff43, 0xff48, 0xff41, + 0xff52, 0xff53, 0xff45, 0xff54, + 0xff3f, 0xff35, 0xff34, 0xff26, + 0xff0d, 0xff13, 0xff12, 0xff2c, + 0xff25, 0xff0c, 0xff3f, 0xff23, + 0xff33, 0xff54, 0xff44, 0xff33, + 0xff54, 0xff52, 0xff49, 0xff4e, + 0xff47, 0xff13, 0xff12, 0xff3f, +#ifdef TARGET_DARWIN + 0x0 }; +#else + 0x1f42d, 0x1f42e, 0x0 }; +#endif + +static const uint16_t refutf16BE[] = { 0x54ff, 0x45ff, 0x53ff, 0x54ff, + 0x3fff, 0x55ff, 0x54ff, 0x46ff, + 0x11ff, 0x16ff, 0x22ff, 0x25ff, + 0x54ff, 0x4fff, 0x35ff, 0x34ff, + 0x26ff, 0x18ff, 0x0}; + +static const uint16_t refucs2[] = { 0xff54, 0xff45, 0xff53, 0xff54, + 0xff3f, 0xff55, 0xff43, 0xff53, + 0xff12, 0xff54, 0xff4f, 0xff35, + 0xff34, 0xff26, 0xff18, 0x0 }; +#endif + +class TestCharsetConverter : public testing::Test +{ +protected: + TestCharsetConverter() + { + /* Add default settings for locale. + * Settings here are taken from CGUISettings::Initialize() + */ + /* + //! @todo implement + CSettingsCategory *loc = CServiceBroker::GetSettingsComponent()->GetSettings()->AddCategory(7, "locale", 14090); + CServiceBroker::GetSettingsComponent()->GetSettings()->AddString(loc, CSettings::SETTING_LOCALE_LANGUAGE,248,"english", + SPIN_CONTROL_TEXT); + CServiceBroker::GetSettingsComponent()->GetSettings()->AddString(loc, CSettings::SETTING_LOCALE_COUNTRY, 20026, "USA", + SPIN_CONTROL_TEXT); + CServiceBroker::GetSettingsComponent()->GetSettings()->AddString(loc, CSettings::SETTING_LOCALE_CHARSET, 14091, "DEFAULT", + SPIN_CONTROL_TEXT); // charset is set by the + // language file + + // Add default settings for subtitles + CSettingsCategory *sub = CServiceBroker::GetSettingsComponent()->GetSettings()->AddCategory(5, "subtitles", 287); + CServiceBroker::GetSettingsComponent()->GetSettings()->AddString(sub, CSettings::SETTING_SUBTITLES_CHARSET, 735, "DEFAULT", + SPIN_CONTROL_TEXT); + */ + g_charsetConverter.reset(); + g_charsetConverter.clear(); + } + + ~TestCharsetConverter() override + { + CServiceBroker::GetSettingsComponent()->GetSettings()->Unload(); + } + + std::string refstra1, refstra2, varstra1; + std::wstring refstrw1, varstrw1; + std::string refstr1; +}; + +TEST_F(TestCharsetConverter, utf8ToW) +{ + refstra1 = "test utf8ToW"; + refstrw1 = L"test utf8ToW"; + varstrw1.clear(); + g_charsetConverter.utf8ToW(refstra1, varstrw1, true, false, false); + EXPECT_STREQ(refstrw1.c_str(), varstrw1.c_str()); +} + + +//TEST_F(TestCharsetConverter, utf16LEtoW) +//{ +// refstrw1 = L"test_utf16LEtow"; +// //! @todo Should be able to use '=' operator instead of assign() +// std::wstring refstr16_1; +// refstr16_1.assign(refutf16LE1); +// varstrw1.clear(); +// g_charsetConverter.utf16LEtoW(refstr16_1, varstrw1); +// EXPECT_STREQ(refstrw1.c_str(), varstrw1.c_str()); +//} + +TEST_F(TestCharsetConverter, subtitleCharsetToUtf8) +{ + refstra1 = "test subtitleCharsetToW"; + varstra1.clear(); + g_charsetConverter.subtitleCharsetToUtf8(refstra1, varstra1); + + /* Assign refstra1 to refstrw1 so that we can compare */ + EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +} + +TEST_F(TestCharsetConverter, utf8ToStringCharset_1) +{ + refstra1 = "test utf8ToStringCharset"; + varstra1.clear(); + g_charsetConverter.utf8ToStringCharset(refstra1, varstra1); + EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +} + +TEST_F(TestCharsetConverter, utf8ToStringCharset_2) +{ + refstra1 = "test utf8ToStringCharset"; + varstra1 = "test utf8ToStringCharset"; + g_charsetConverter.utf8ToStringCharset(varstra1); + EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +} + +TEST_F(TestCharsetConverter, utf8ToSystem) +{ + refstra1 = "test utf8ToSystem"; + varstra1 = "test utf8ToSystem"; + g_charsetConverter.utf8ToSystem(varstra1); + EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +} + +TEST_F(TestCharsetConverter, utf8To_ASCII) +{ + refstra1 = "test utf8To: charset ASCII, std::string"; + varstra1.clear(); + g_charsetConverter.utf8To("ASCII", refstra1, varstra1); + EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +} + +/* +TEST_F(TestCharsetConverter, utf8To_UTF16LE) +{ + refstra1 = "test_utf8To:_charset_UTF-16LE,_" + "CStdString16"; + refstr16_1.assign(refutf16LE2); + varstr16_1.clear(); + g_charsetConverter.utf8To("UTF-16LE", refstra1, varstr16_1); + EXPECT_TRUE(!memcmp(refstr16_1.c_str(), varstr16_1.c_str(), + refstr16_1.length() * sizeof(uint16_t))); +} +*/ + +//TEST_F(TestCharsetConverter, utf8To_UTF32LE) +//{ +// refstra1 = "test_utf8To:_charset_UTF-32LE,_" +//#ifdef TARGET_DARWIN +///* OSX has its own 'special' utf-8 charset which we use (see UTF8_SOURCE in CharsetConverter.cpp) +// which is basically NFD (decomposed) utf-8. The trouble is, it fails on the COW FACE and MOUSE FACE +// characters for some reason (possibly anything over 0x100000, or maybe there's a decomposed form of these +// that I couldn't find???) If UTF8_SOURCE is switched to UTF-8 then this test would pass as-is, but then +// some filenames stored in utf8-mac wouldn't display correctly in the UI. */ +// "CStdString32_"; +//#else +// "CStdString32_🐭🐮"; +//#endif +// refstr32_1.assign(refutf32LE1); +// varstr32_1.clear(); +// g_charsetConverter.utf8To("UTF-32LE", refstra1, varstr32_1); +// EXPECT_TRUE(!memcmp(refstr32_1.c_str(), varstr32_1.c_str(), +// sizeof(refutf32LE1))); +//} + +TEST_F(TestCharsetConverter, stringCharsetToUtf8) +{ + refstra1 = "test_stringCharsetToUtf8"; + varstra1.clear(); + g_charsetConverter.ToUtf8("UTF-16LE", refutf16LE3, varstra1); + EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +} + +TEST_F(TestCharsetConverter, isValidUtf8_1) +{ + varstra1.clear(); + g_charsetConverter.ToUtf8("UTF-16LE", refutf16LE3, varstra1); + EXPECT_TRUE(CUtf8Utils::isValidUtf8(varstra1.c_str())); +} + +TEST_F(TestCharsetConverter, isValidUtf8_2) +{ + refstr1 = refutf16LE3; + EXPECT_FALSE(CUtf8Utils::isValidUtf8(refstr1)); +} + +TEST_F(TestCharsetConverter, isValidUtf8_3) +{ + varstra1.clear(); + g_charsetConverter.ToUtf8("UTF-16LE", refutf16LE3, varstra1); + EXPECT_TRUE(CUtf8Utils::isValidUtf8(varstra1.c_str())); +} + +TEST_F(TestCharsetConverter, isValidUtf8_4) +{ + EXPECT_FALSE(CUtf8Utils::isValidUtf8(refutf16LE3)); +} + +//! @todo Resolve correct input/output for this function +// TEST_F(TestCharsetConverter, ucs2CharsetToStringCharset) +// { +// void ucs2CharsetToStringCharset(const std::wstring& strSource, +// std::string& strDest, bool swap = false); +// } + +TEST_F(TestCharsetConverter, wToUTF8) +{ + refstrw1 = L"test_wToUTF8"; + refstra1 = u8"test_wToUTF8"; + varstra1.clear(); + g_charsetConverter.wToUTF8(refstrw1, varstra1); + EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +} + +//TEST_F(TestCharsetConverter, utf16BEtoUTF8) +//{ +// refstr16_1.assign(refutf16BE); +// refstra1 = "test_utf16BEtoUTF8"; +// varstra1.clear(); +// g_charsetConverter.utf16BEtoUTF8(refstr16_1, varstra1); +// EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +//} + +//TEST_F(TestCharsetConverter, utf16LEtoUTF8) +//{ +// refstr16_1.assign(refutf16LE4); +// refstra1 = "test_utf16LEtoUTF8"; +// varstra1.clear(); +// g_charsetConverter.utf16LEtoUTF8(refstr16_1, varstra1); +// EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +//} + +//TEST_F(TestCharsetConverter, ucs2ToUTF8) +//{ +// refstr16_1.assign(refucs2); +// refstra1 = "test_ucs2toUTF8"; +// varstra1.clear(); +// g_charsetConverter.ucs2ToUTF8(refstr16_1, varstra1); +// EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +//} + +TEST_F(TestCharsetConverter, utf8logicalToVisualBiDi) +{ + refstra1 = "test_utf8logicalToVisualBiDi"; + refstra2 = "test_utf8logicalToVisualBiDi"; + varstra1.clear(); + g_charsetConverter.utf8logicalToVisualBiDi(refstra1, varstra1); + EXPECT_STREQ(refstra2.c_str(), varstra1.c_str()); +} + +//! @todo Resolve correct input/output for this function +// TEST_F(TestCharsetConverter, utf32ToStringCharset) +// { +// void utf32ToStringCharset(const unsigned long* strSource, std::string& strDest); +// } + +TEST_F(TestCharsetConverter, getCharsetLabels) +{ + std::vector<std::string> reflabels; + reflabels.emplace_back("Western Europe (ISO)"); + reflabels.emplace_back("Central Europe (ISO)"); + reflabels.emplace_back("South Europe (ISO)"); + reflabels.emplace_back("Baltic (ISO)"); + reflabels.emplace_back("Cyrillic (ISO)"); + reflabels.emplace_back("Arabic (ISO)"); + reflabels.emplace_back("Greek (ISO)"); + reflabels.emplace_back("Hebrew (ISO)"); + reflabels.emplace_back("Turkish (ISO)"); + reflabels.emplace_back("Central Europe (Windows)"); + reflabels.emplace_back("Cyrillic (Windows)"); + reflabels.emplace_back("Western Europe (Windows)"); + reflabels.emplace_back("Greek (Windows)"); + reflabels.emplace_back("Turkish (Windows)"); + reflabels.emplace_back("Hebrew (Windows)"); + reflabels.emplace_back("Arabic (Windows)"); + reflabels.emplace_back("Baltic (Windows)"); + reflabels.emplace_back("Vietnamese (Windows)"); + reflabels.emplace_back("Thai (Windows)"); + reflabels.emplace_back("Chinese Traditional (Big5)"); + reflabels.emplace_back("Chinese Simplified (GBK)"); + reflabels.emplace_back("Japanese (Shift-JIS)"); + reflabels.emplace_back("Korean"); + reflabels.emplace_back("Hong Kong (Big5-HKSCS)"); + + std::vector<std::string> varlabels = g_charsetConverter.getCharsetLabels(); + ASSERT_EQ(reflabels.size(), varlabels.size()); + + size_t pos = 0; + for (const auto& it : varlabels) + { + EXPECT_STREQ((reflabels.at(pos++)).c_str(), it.c_str()); + } +} + +TEST_F(TestCharsetConverter, getCharsetLabelByName) +{ + std::string varstr = + g_charsetConverter.getCharsetLabelByName("ISO-8859-1"); + EXPECT_STREQ("Western Europe (ISO)", varstr.c_str()); + varstr.clear(); + varstr = g_charsetConverter.getCharsetLabelByName("Bogus"); + EXPECT_STREQ("", varstr.c_str()); +} + +TEST_F(TestCharsetConverter, getCharsetNameByLabel) +{ + std::string varstr = + g_charsetConverter.getCharsetNameByLabel("Western Europe (ISO)"); + EXPECT_STREQ("ISO-8859-1", varstr.c_str()); + varstr.clear(); + varstr = g_charsetConverter.getCharsetNameByLabel("Bogus"); + EXPECT_STREQ("", varstr.c_str()); +} + +TEST_F(TestCharsetConverter, unknownToUTF8_1) +{ + refstra1 = "test_unknownToUTF8"; + varstra1 = "test_unknownToUTF8"; + g_charsetConverter.unknownToUTF8(varstra1); + EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +} + +TEST_F(TestCharsetConverter, unknownToUTF8_2) +{ + refstra1 = "test_unknownToUTF8"; + varstra1.clear(); + g_charsetConverter.unknownToUTF8(refstra1, varstra1); + EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +} + +TEST_F(TestCharsetConverter, toW) +{ + refstra1 = "test_toW:_charset_UTF-16LE"; + refstrw1 = L"\xBDEF\xEF94\x85BD\xBDEF\xEF93\x94BD\xBCEF\xEFBF" + L"\x94BD\xBDEF\xEF8F\xB7BC\xBCEF\xEF9A\xBFBC\xBDEF" + L"\xEF83\x88BD\xBDEF\xEF81\x92BD\xBDEF\xEF93\x85BD" + L"\xBDEF\xEF94\xBFBC\xBCEF\xEFB5\xB4BC\xBCEF\xEFA6" + L"\x8DBC\xBCEF\xEF91\x96BC\xBCEF\xEFAC\xA5BC"; + varstrw1.clear(); + g_charsetConverter.toW(refstra1, varstrw1, "UTF-16LE"); + EXPECT_STREQ(refstrw1.c_str(), varstrw1.c_str()); +} + +TEST_F(TestCharsetConverter, fromW) +{ + refstrw1 = L"\xBDEF\xEF94\x85BD\xBDEF\xEF93\x94BD\xBCEF\xEFBF" + L"\x86BD\xBDEF\xEF92\x8FBD\xBDEF\xEF8D\xB7BC\xBCEF" + L"\xEF9A\xBFBC\xBDEF\xEF83\x88BD\xBDEF\xEF81\x92BD" + L"\xBDEF\xEF93\x85BD\xBDEF\xEF94\xBFBC\xBCEF\xEFB5" + L"\xB4BC\xBCEF\xEFA6\x8DBC\xBCEF\xEF91\x96BC\xBCEF" + L"\xEFAC\xA5BC"; + refstra1 = "test_fromW:_charset_UTF-16LE"; + varstra1.clear(); + g_charsetConverter.fromW(refstrw1, varstra1, "UTF-16LE"); + EXPECT_STREQ(refstra1.c_str(), varstra1.c_str()); +} diff --git a/xbmc/utils/test/TestComponentContainer.cpp b/xbmc/utils/test/TestComponentContainer.cpp new file mode 100644 index 0000000..d7246be --- /dev/null +++ b/xbmc/utils/test/TestComponentContainer.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/ComponentContainer.h" + +#include <utility> + +#include <gtest/gtest.h> + +class BaseTestType +{ +public: + virtual ~BaseTestType() = default; +}; + +struct DerivedType1 : public BaseTestType +{ + int a = 1; +}; + +struct DerivedType2 : public BaseTestType +{ + int a = 2; +}; + +struct DerivedType3 : public BaseTestType +{ + int a = 3; +}; + +class TestContainer : public CComponentContainer<BaseTestType> +{ + FRIEND_TEST(TestComponentContainer, Generic); +}; + +TEST(TestComponentContainer, Generic) +{ + TestContainer container; + + // check that we can register types + container.RegisterComponent(std::make_shared<DerivedType1>()); + EXPECT_EQ(container.size(), 1u); + container.RegisterComponent(std::make_shared<DerivedType2>()); + EXPECT_EQ(container.size(), 2u); + + // check that trying to register a component twice does nothing + container.RegisterComponent(std::make_shared<DerivedType2>()); + EXPECT_EQ(container.size(), 2u); + + // check that first component is valid + const auto t1 = container.GetComponent<DerivedType1>(); + EXPECT_TRUE(t1 != nullptr); + EXPECT_EQ(t1->a, 1); + + // check that second component is valid + const auto t2 = container.GetComponent<DerivedType2>(); + EXPECT_TRUE(t2 != nullptr); + EXPECT_EQ(t2->a, 2); + + // check that third component is not there + EXPECT_THROW(container.GetComponent<DerivedType3>(), std::logic_error); + + // check that component instance is constant + const auto t4 = container.GetComponent<DerivedType1>(); + EXPECT_EQ(t1.get(), t4.get()); + + // check we can call the const overload for GetComponent + // and that the returned type is const + const auto t5 = const_cast<const TestContainer&>(container).GetComponent<DerivedType1>(); + EXPECT_TRUE(std::is_const_v<typename decltype(t5)::element_type>); +} diff --git a/xbmc/utils/test/TestCrc32.cpp b/xbmc/utils/test/TestCrc32.cpp new file mode 100644 index 0000000..99a2dd5 --- /dev/null +++ b/xbmc/utils/test/TestCrc32.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/Crc32.h" + +#include <gtest/gtest.h> + +static const char refdata[] = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "01234567890!@#$%^&*()"; + +TEST(TestCrc32, Compute_1) +{ + Crc32 a; + uint32_t varcrc; + a.Compute(refdata, sizeof(refdata) - 1); + varcrc = a; + EXPECT_EQ(0xa4eb60e3, varcrc); +} + +TEST(TestCrc32, Compute_2) +{ + uint32_t varcrc; + std::string s = refdata; + varcrc = Crc32::Compute(s); + EXPECT_EQ(0xa4eb60e3, varcrc); +} + +TEST(TestCrc32, ComputeFromLowerCase) +{ + std::string s = refdata; + uint32_t varcrc = Crc32::ComputeFromLowerCase(s); + EXPECT_EQ((uint32_t)0x7f045b3e, varcrc); +} + +TEST(TestCrc32, Reset) +{ + Crc32 a; + uint32_t varcrc; + std::string s = refdata; + a.Compute(s.c_str(), s.length()); + a.Reset(); + varcrc = a; + EXPECT_EQ(0xffffffff, varcrc); +} diff --git a/xbmc/utils/test/TestDatabaseUtils.cpp b/xbmc/utils/test/TestDatabaseUtils.cpp new file mode 100644 index 0000000..ddb986c --- /dev/null +++ b/xbmc/utils/test/TestDatabaseUtils.cpp @@ -0,0 +1,1377 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "dbwrappers/qry_dat.h" +#include "music/MusicDatabase.h" +#include "utils/DatabaseUtils.h" +#include "utils/StringUtils.h" +#include "utils/Variant.h" +#include "video/VideoDatabase.h" + +#include <gtest/gtest.h> + +class TestDatabaseUtilsHelper +{ +public: + TestDatabaseUtilsHelper() + { + album_idAlbum = CMusicDatabase::album_idAlbum; + album_strAlbum = CMusicDatabase::album_strAlbum; + album_strArtists = CMusicDatabase::album_strArtists; + album_strGenres = CMusicDatabase::album_strGenres; + album_strMoods = CMusicDatabase::album_strMoods; + album_strReleaseDate = CMusicDatabase::album_strReleaseDate; + album_strOrigReleaseDate = CMusicDatabase::album_strOrigReleaseDate; + album_strStyles = CMusicDatabase::album_strStyles; + album_strThemes = CMusicDatabase::album_strThemes; + album_strReview = CMusicDatabase::album_strReview; + album_strLabel = CMusicDatabase::album_strLabel; + album_strType = CMusicDatabase::album_strType; + album_fRating = CMusicDatabase::album_fRating; + album_iVotes = CMusicDatabase::album_iVotes; + album_iUserrating = CMusicDatabase::album_iUserrating; + album_dtDateAdded = CMusicDatabase::album_dateAdded; + + song_idSong = CMusicDatabase::song_idSong; + song_strTitle = CMusicDatabase::song_strTitle; + song_iTrack = CMusicDatabase::song_iTrack; + song_iDuration = CMusicDatabase::song_iDuration; + song_strReleaseDate = CMusicDatabase::song_strReleaseDate; + song_strOrigReleaseDate = CMusicDatabase::song_strOrigReleaseDate; + song_strFileName = CMusicDatabase::song_strFileName; + song_iTimesPlayed = CMusicDatabase::song_iTimesPlayed; + song_iStartOffset = CMusicDatabase::song_iStartOffset; + song_iEndOffset = CMusicDatabase::song_iEndOffset; + song_lastplayed = CMusicDatabase::song_lastplayed; + song_rating = CMusicDatabase::song_rating; + song_votes = CMusicDatabase::song_votes; + song_userrating = CMusicDatabase::song_userrating; + song_comment = CMusicDatabase::song_comment; + song_strAlbum = CMusicDatabase::song_strAlbum; + song_strPath = CMusicDatabase::song_strPath; + song_strGenres = CMusicDatabase::song_strGenres; + song_strArtists = CMusicDatabase::song_strArtists; + } + + int album_idAlbum; + int album_strAlbum; + int album_strArtists; + int album_strGenres; + int album_strMoods; + int album_strReleaseDate; + int album_strOrigReleaseDate; + int album_strStyles; + int album_strThemes; + int album_strReview; + int album_strLabel; + int album_strType; + int album_fRating; + int album_iVotes; + int album_iUserrating; + int album_dtDateAdded; + + int song_idSong; + int song_strTitle; + int song_iTrack; + int song_iDuration; + int song_strReleaseDate; + int song_strOrigReleaseDate; + int song_strFileName; + int song_iTimesPlayed; + int song_iStartOffset; + int song_iEndOffset; + int song_lastplayed; + int song_rating; + int song_votes; + int song_userrating; + int song_comment; + int song_strAlbum; + int song_strPath; + int song_strGenres; + int song_strArtists; +}; + +TEST(TestDatabaseUtils, GetField_None) +{ + std::string refstr, varstr; + + refstr = ""; + varstr = DatabaseUtils::GetField(FieldNone, MediaTypeNone, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + varstr = DatabaseUtils::GetField(FieldNone, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestDatabaseUtils, GetField_MediaTypeAlbum) +{ + std::string refstr, varstr; + + refstr = "albumview.idAlbum"; + varstr = DatabaseUtils::GetField(FieldId, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strAlbum"; + varstr = DatabaseUtils::GetField(FieldAlbum, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strArtists"; + varstr = DatabaseUtils::GetField(FieldArtist, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strArtists"; + varstr = DatabaseUtils::GetField(FieldAlbumArtist, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strGenres"; + varstr = DatabaseUtils::GetField(FieldGenre, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strReleaseDate"; + varstr = DatabaseUtils::GetField(FieldYear, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + +refstr = "albumview.strOrigReleaseDate"; + varstr = DatabaseUtils::GetField(FieldOrigYear, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strMoods"; + varstr = DatabaseUtils::GetField(FieldMoods, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strStyles"; + varstr = DatabaseUtils::GetField(FieldStyles, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strThemes"; + varstr = DatabaseUtils::GetField(FieldThemes, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strReview"; + varstr = DatabaseUtils::GetField(FieldReview, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strLabel"; + varstr = DatabaseUtils::GetField(FieldMusicLabel, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strType"; + varstr = DatabaseUtils::GetField(FieldAlbumType, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.fRating"; + varstr = DatabaseUtils::GetField(FieldRating, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.iVotes"; + varstr = DatabaseUtils::GetField(FieldVotes, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.iUserrating"; + varstr = DatabaseUtils::GetField(FieldUserRating, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.dateAdded"; + varstr = DatabaseUtils::GetField(FieldDateAdded, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = ""; + varstr = DatabaseUtils::GetField(FieldNone, MediaTypeAlbum, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "albumview.strAlbum"; + varstr = DatabaseUtils::GetField(FieldAlbum, MediaTypeAlbum, + DatabaseQueryPartWhere); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + varstr = DatabaseUtils::GetField(FieldAlbum, MediaTypeAlbum, + DatabaseQueryPartOrderBy); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestDatabaseUtils, GetField_MediaTypeSong) +{ + std::string refstr, varstr; + + refstr = "songview.idSong"; + varstr = DatabaseUtils::GetField(FieldId, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.strTitle"; + varstr = DatabaseUtils::GetField(FieldTitle, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.iTrack"; + varstr = DatabaseUtils::GetField(FieldTrackNumber, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.iDuration"; + varstr = DatabaseUtils::GetField(FieldTime, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.strFilename"; + varstr = DatabaseUtils::GetField(FieldFilename, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.iTimesPlayed"; + varstr = DatabaseUtils::GetField(FieldPlaycount, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.iStartOffset"; + varstr = DatabaseUtils::GetField(FieldStartOffset, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.iEndOffset"; + varstr = DatabaseUtils::GetField(FieldEndOffset, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.lastPlayed"; + varstr = DatabaseUtils::GetField(FieldLastPlayed, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.rating"; + varstr = DatabaseUtils::GetField(FieldRating, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.votes"; + varstr = DatabaseUtils::GetField(FieldVotes, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.userrating"; + varstr = DatabaseUtils::GetField(FieldUserRating, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.comment"; + varstr = DatabaseUtils::GetField(FieldComment, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.strReleaseDate"; + varstr = DatabaseUtils::GetField(FieldYear, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.strOrigReleaseDate"; + varstr = DatabaseUtils::GetField(FieldOrigYear, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.strAlbum"; + varstr = DatabaseUtils::GetField(FieldAlbum, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.strPath"; + varstr = DatabaseUtils::GetField(FieldPath, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.strArtists"; + varstr = DatabaseUtils::GetField(FieldArtist, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.strArtists"; + varstr = DatabaseUtils::GetField(FieldAlbumArtist, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.strGenres"; + varstr = DatabaseUtils::GetField(FieldGenre, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.dateAdded"; + varstr = DatabaseUtils::GetField(FieldDateAdded, MediaTypeSong, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "songview.strPath"; + varstr = DatabaseUtils::GetField(FieldPath, MediaTypeSong, + DatabaseQueryPartWhere); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + varstr = DatabaseUtils::GetField(FieldPath, MediaTypeSong, + DatabaseQueryPartOrderBy); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestDatabaseUtils, GetField_MediaTypeMusicVideo) +{ + std::string refstr, varstr; + + refstr = "musicvideo_view.idMVideo"; + varstr = DatabaseUtils::GetField(FieldId, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("musicvideo_view.c{:02}", VIDEODB_ID_MUSICVIDEO_TITLE); + varstr = DatabaseUtils::GetField(FieldTitle, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("musicvideo_view.c{:02}", VIDEODB_ID_MUSICVIDEO_RUNTIME); + varstr = DatabaseUtils::GetField(FieldTime, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("musicvideo_view.c{:02}", VIDEODB_ID_MUSICVIDEO_DIRECTOR); + varstr = DatabaseUtils::GetField(FieldDirector, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("musicvideo_view.c{:02}", VIDEODB_ID_MUSICVIDEO_STUDIOS); + varstr = DatabaseUtils::GetField(FieldStudio, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("musicvideo_view.c{:02}", VIDEODB_ID_MUSICVIDEO_PLOT); + varstr = DatabaseUtils::GetField(FieldPlot, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("musicvideo_view.c{:02}", VIDEODB_ID_MUSICVIDEO_ALBUM); + varstr = DatabaseUtils::GetField(FieldAlbum, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("musicvideo_view.c{:02}", VIDEODB_ID_MUSICVIDEO_ARTIST); + varstr = DatabaseUtils::GetField(FieldArtist, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("musicvideo_view.c{:02}", VIDEODB_ID_MUSICVIDEO_GENRE); + varstr = DatabaseUtils::GetField(FieldGenre, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("musicvideo_view.c{:02}", VIDEODB_ID_MUSICVIDEO_TRACK); + varstr = DatabaseUtils::GetField(FieldTrackNumber, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "musicvideo_view.strFilename"; + varstr = DatabaseUtils::GetField(FieldFilename, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "musicvideo_view.strPath"; + varstr = DatabaseUtils::GetField(FieldPath, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "musicvideo_view.playCount"; + varstr = DatabaseUtils::GetField(FieldPlaycount, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "musicvideo_view.lastPlayed"; + varstr = DatabaseUtils::GetField(FieldLastPlayed, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "musicvideo_view.dateAdded"; + varstr = DatabaseUtils::GetField(FieldDateAdded, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = ""; + varstr = DatabaseUtils::GetField(FieldVideoResolution, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "musicvideo_view.strPath"; + varstr = DatabaseUtils::GetField(FieldPath, MediaTypeMusicVideo, + DatabaseQueryPartWhere); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "musicvideo_view.strPath"; + varstr = DatabaseUtils::GetField(FieldPath, MediaTypeMusicVideo, + DatabaseQueryPartOrderBy); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "musicvideo_view.userrating"; + varstr = DatabaseUtils::GetField(FieldUserRating, MediaTypeMusicVideo, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestDatabaseUtils, GetField_MediaTypeMovie) +{ + std::string refstr, varstr; + + refstr = "movie_view.idMovie"; + varstr = DatabaseUtils::GetField(FieldId, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c{:02}", VIDEODB_ID_TITLE); + varstr = DatabaseUtils::GetField(FieldTitle, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("CASE WHEN length(movie_view.c{:02}) > 0 THEN movie_view.c{:02} " + "ELSE movie_view.c{:02} END", + VIDEODB_ID_SORTTITLE, VIDEODB_ID_SORTTITLE, VIDEODB_ID_TITLE); + varstr = DatabaseUtils::GetField(FieldTitle, MediaTypeMovie, + DatabaseQueryPartOrderBy); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c{:02}", VIDEODB_ID_PLOT); + varstr = DatabaseUtils::GetField(FieldPlot, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c{:02}", VIDEODB_ID_PLOTOUTLINE); + varstr = DatabaseUtils::GetField(FieldPlotOutline, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c{:02}", VIDEODB_ID_TAGLINE); + varstr = DatabaseUtils::GetField(FieldTagline, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "movie_view.votes"; + varstr = DatabaseUtils::GetField(FieldVotes, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "movie_view.rating"; + varstr = DatabaseUtils::GetField(FieldRating, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c{:02}", VIDEODB_ID_CREDITS); + varstr = DatabaseUtils::GetField(FieldWriter, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c{:02}", VIDEODB_ID_SORTTITLE); + varstr = DatabaseUtils::GetField(FieldSortTitle, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c{:02}", VIDEODB_ID_RUNTIME); + varstr = DatabaseUtils::GetField(FieldTime, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c{:02}", VIDEODB_ID_MPAA); + varstr = DatabaseUtils::GetField(FieldMPAA, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c{:02}", VIDEODB_ID_TOP250); + varstr = DatabaseUtils::GetField(FieldTop250, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c{:02}", VIDEODB_ID_GENRE); + varstr = DatabaseUtils::GetField(FieldGenre, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c{:02}", VIDEODB_ID_DIRECTOR); + varstr = DatabaseUtils::GetField(FieldDirector, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c{:02}", VIDEODB_ID_STUDIOS); + varstr = DatabaseUtils::GetField(FieldStudio, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c{:02}", VIDEODB_ID_TRAILER); + varstr = DatabaseUtils::GetField(FieldTrailer, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("movie_view.c{:02}", VIDEODB_ID_COUNTRY); + varstr = DatabaseUtils::GetField(FieldCountry, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "movie_view.strFilename"; + varstr = DatabaseUtils::GetField(FieldFilename, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "movie_view.strPath"; + varstr = DatabaseUtils::GetField(FieldPath, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "movie_view.playCount"; + varstr = DatabaseUtils::GetField(FieldPlaycount, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "movie_view.lastPlayed"; + varstr = DatabaseUtils::GetField(FieldLastPlayed, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "movie_view.dateAdded"; + varstr = DatabaseUtils::GetField(FieldDateAdded, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "movie_view.userrating"; + varstr = DatabaseUtils::GetField(FieldUserRating, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = ""; + varstr = DatabaseUtils::GetField(FieldRandom, MediaTypeMovie, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestDatabaseUtils, GetField_MediaTypeTvShow) +{ + std::string refstr, varstr; + + refstr = "tvshow_view.idShow"; + varstr = DatabaseUtils::GetField(FieldId, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = + StringUtils::Format("CASE WHEN length(tvshow_view.c{:02}) > 0 THEN tvshow_view.c{:02} " + "ELSE tvshow_view.c{:02} END", + VIDEODB_ID_TV_SORTTITLE, VIDEODB_ID_TV_SORTTITLE, VIDEODB_ID_TV_TITLE); + varstr = DatabaseUtils::GetField(FieldTitle, MediaTypeTvShow, + DatabaseQueryPartOrderBy); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("tvshow_view.c{:02}", VIDEODB_ID_TV_TITLE); + varstr = DatabaseUtils::GetField(FieldTitle, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("tvshow_view.c{:02}", VIDEODB_ID_TV_PLOT); + varstr = DatabaseUtils::GetField(FieldPlot, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("tvshow_view.c{:02}", VIDEODB_ID_TV_STATUS); + varstr = DatabaseUtils::GetField(FieldTvShowStatus, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "tvshow_view.votes"; + varstr = DatabaseUtils::GetField(FieldVotes, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "tvshow_view.rating"; + varstr = DatabaseUtils::GetField(FieldRating, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("tvshow_view.c{:02}", VIDEODB_ID_TV_PREMIERED); + varstr = DatabaseUtils::GetField(FieldYear, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("tvshow_view.c{:02}", VIDEODB_ID_TV_GENRE); + varstr = DatabaseUtils::GetField(FieldGenre, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("tvshow_view.c{:02}", VIDEODB_ID_TV_MPAA); + varstr = DatabaseUtils::GetField(FieldMPAA, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("tvshow_view.c{:02}", VIDEODB_ID_TV_STUDIOS); + varstr = DatabaseUtils::GetField(FieldStudio, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("tvshow_view.c{:02}", VIDEODB_ID_TV_SORTTITLE); + varstr = DatabaseUtils::GetField(FieldSortTitle, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "tvshow_view.strPath"; + varstr = DatabaseUtils::GetField(FieldPath, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "tvshow_view.dateAdded"; + varstr = DatabaseUtils::GetField(FieldDateAdded, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "tvshow_view.totalSeasons"; + varstr = DatabaseUtils::GetField(FieldSeason, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "tvshow_view.totalCount"; + varstr = DatabaseUtils::GetField(FieldNumberOfEpisodes, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "tvshow_view.watchedcount"; + varstr = DatabaseUtils::GetField(FieldNumberOfWatchedEpisodes, + MediaTypeTvShow, DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "tvshow_view.userrating"; + varstr = DatabaseUtils::GetField(FieldUserRating, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = ""; + varstr = DatabaseUtils::GetField(FieldRandom, MediaTypeTvShow, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestDatabaseUtils, GetField_MediaTypeEpisode) +{ + std::string refstr, varstr; + + refstr = "episode_view.idEpisode"; + varstr = DatabaseUtils::GetField(FieldId, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("episode_view.c{:02}", VIDEODB_ID_EPISODE_TITLE); + varstr = DatabaseUtils::GetField(FieldTitle, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("episode_view.c{:02}", VIDEODB_ID_EPISODE_PLOT); + varstr = DatabaseUtils::GetField(FieldPlot, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.votes"; + varstr = DatabaseUtils::GetField(FieldVotes, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.rating"; + varstr = DatabaseUtils::GetField(FieldRating, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("episode_view.c{:02}", VIDEODB_ID_EPISODE_CREDITS); + varstr = DatabaseUtils::GetField(FieldWriter, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("episode_view.c{:02}", VIDEODB_ID_EPISODE_AIRED); + varstr = DatabaseUtils::GetField(FieldAirDate, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("episode_view.c{:02}", VIDEODB_ID_EPISODE_RUNTIME); + varstr = DatabaseUtils::GetField(FieldTime, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("episode_view.c{:02}", VIDEODB_ID_EPISODE_DIRECTOR); + varstr = DatabaseUtils::GetField(FieldDirector, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("episode_view.c{:02}", VIDEODB_ID_EPISODE_SEASON); + varstr = DatabaseUtils::GetField(FieldSeason, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = StringUtils::Format("episode_view.c{:02}", VIDEODB_ID_EPISODE_EPISODE); + varstr = DatabaseUtils::GetField(FieldEpisodeNumber, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.strFilename"; + varstr = DatabaseUtils::GetField(FieldFilename, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.strPath"; + varstr = DatabaseUtils::GetField(FieldPath, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.playCount"; + varstr = DatabaseUtils::GetField(FieldPlaycount, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.lastPlayed"; + varstr = DatabaseUtils::GetField(FieldLastPlayed, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.dateAdded"; + varstr = DatabaseUtils::GetField(FieldDateAdded, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.strTitle"; + varstr = DatabaseUtils::GetField(FieldTvShowTitle, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.premiered"; + varstr = DatabaseUtils::GetField(FieldYear, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.mpaa"; + varstr = DatabaseUtils::GetField(FieldMPAA, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.strStudio"; + varstr = DatabaseUtils::GetField(FieldStudio, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "episode_view.userrating"; + varstr = DatabaseUtils::GetField(FieldUserRating, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = ""; + varstr = DatabaseUtils::GetField(FieldRandom, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestDatabaseUtils, GetField_FieldRandom) +{ + std::string refstr, varstr; + + refstr = ""; + varstr = DatabaseUtils::GetField(FieldRandom, MediaTypeEpisode, + DatabaseQueryPartSelect); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = ""; + varstr = DatabaseUtils::GetField(FieldRandom, MediaTypeEpisode, + DatabaseQueryPartWhere); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "RANDOM()"; + varstr = DatabaseUtils::GetField(FieldRandom, MediaTypeEpisode, + DatabaseQueryPartOrderBy); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestDatabaseUtils, GetFieldIndex_None) +{ + int refindex, varindex; + + refindex = -1; + varindex = DatabaseUtils::GetFieldIndex(FieldRandom, MediaTypeNone); + EXPECT_EQ(refindex, varindex); + + varindex = DatabaseUtils::GetFieldIndex(FieldNone, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); +} + +//! @todo Should enums in CMusicDatabase be made public instead? +TEST(TestDatabaseUtils, GetFieldIndex_MediaTypeAlbum) +{ + int refindex, varindex; + TestDatabaseUtilsHelper a; + + refindex = a.album_idAlbum; + varindex = DatabaseUtils::GetFieldIndex(FieldId, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strAlbum; + varindex = DatabaseUtils::GetFieldIndex(FieldAlbum, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strArtists; + varindex = DatabaseUtils::GetFieldIndex(FieldArtist, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strArtists; + varindex = DatabaseUtils::GetFieldIndex(FieldAlbumArtist, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strGenres; + varindex = DatabaseUtils::GetFieldIndex(FieldGenre, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strReleaseDate; + varindex = DatabaseUtils::GetFieldIndex(FieldYear, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strOrigReleaseDate; + varindex = DatabaseUtils::GetFieldIndex(FieldOrigYear, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strMoods; + varindex = DatabaseUtils::GetFieldIndex(FieldMoods, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strStyles; + varindex = DatabaseUtils::GetFieldIndex(FieldStyles, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strThemes; + varindex = DatabaseUtils::GetFieldIndex(FieldThemes, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strReview; + varindex = DatabaseUtils::GetFieldIndex(FieldReview, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strLabel; + varindex = DatabaseUtils::GetFieldIndex(FieldMusicLabel, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_strType; + varindex = DatabaseUtils::GetFieldIndex(FieldAlbumType, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_fRating; + varindex = DatabaseUtils::GetFieldIndex(FieldRating, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = a.album_dtDateAdded; + varindex = DatabaseUtils::GetFieldIndex(FieldDateAdded, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); + + refindex = -1; + varindex = DatabaseUtils::GetFieldIndex(FieldRandom, MediaTypeAlbum); + EXPECT_EQ(refindex, varindex); +} + +TEST(TestDatabaseUtils, GetFieldIndex_MediaTypeSong) +{ + int refindex, varindex; + TestDatabaseUtilsHelper a; + + refindex = a.song_idSong; + varindex = DatabaseUtils::GetFieldIndex(FieldId, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_strTitle; + varindex = DatabaseUtils::GetFieldIndex(FieldTitle, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_iTrack; + varindex = DatabaseUtils::GetFieldIndex(FieldTrackNumber, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_iDuration; + varindex = DatabaseUtils::GetFieldIndex(FieldTime, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_strReleaseDate; + varindex = DatabaseUtils::GetFieldIndex(FieldYear, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_strFileName; + varindex = DatabaseUtils::GetFieldIndex(FieldFilename, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_iTimesPlayed; + varindex = DatabaseUtils::GetFieldIndex(FieldPlaycount, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_iStartOffset; + varindex = DatabaseUtils::GetFieldIndex(FieldStartOffset, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_iEndOffset; + varindex = DatabaseUtils::GetFieldIndex(FieldEndOffset, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_lastplayed; + varindex = DatabaseUtils::GetFieldIndex(FieldLastPlayed, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_rating; + varindex = DatabaseUtils::GetFieldIndex(FieldRating, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_votes; + varindex = DatabaseUtils::GetFieldIndex(FieldVotes, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_userrating; + varindex = DatabaseUtils::GetFieldIndex(FieldUserRating, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_comment; + varindex = DatabaseUtils::GetFieldIndex(FieldComment, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_strAlbum; + varindex = DatabaseUtils::GetFieldIndex(FieldAlbum, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_strPath; + varindex = DatabaseUtils::GetFieldIndex(FieldPath, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_strArtists; + varindex = DatabaseUtils::GetFieldIndex(FieldArtist, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = a.song_strGenres; + varindex = DatabaseUtils::GetFieldIndex(FieldGenre, MediaTypeSong); + EXPECT_EQ(refindex, varindex); + + refindex = -1; + varindex = DatabaseUtils::GetFieldIndex(FieldRandom, MediaTypeSong); + EXPECT_EQ(refindex, varindex); +} + +TEST(TestDatabaseUtils, GetFieldIndex_MediaTypeMusicVideo) +{ + int refindex, varindex; + + refindex = 0; + varindex = DatabaseUtils::GetFieldIndex(FieldId, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_MUSICVIDEO_TITLE + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldTitle, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_MUSICVIDEO_RUNTIME + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldTime, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_MUSICVIDEO_DIRECTOR + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldDirector, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_MUSICVIDEO_STUDIOS + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldStudio, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_MUSICVIDEO_PLOT + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldPlot, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_MUSICVIDEO_ALBUM + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldAlbum, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_MUSICVIDEO_ARTIST + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldArtist, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_MUSICVIDEO_GENRE + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldGenre, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_MUSICVIDEO_TRACK + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldTrackNumber, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MUSICVIDEO_FILE; + varindex = DatabaseUtils::GetFieldIndex(FieldFilename, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MUSICVIDEO_PATH; + varindex = DatabaseUtils::GetFieldIndex(FieldPath, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MUSICVIDEO_PLAYCOUNT; + varindex = DatabaseUtils::GetFieldIndex(FieldPlaycount, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MUSICVIDEO_LASTPLAYED; + varindex = DatabaseUtils::GetFieldIndex(FieldLastPlayed, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MUSICVIDEO_DATEADDED; + varindex = DatabaseUtils::GetFieldIndex(FieldDateAdded, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MUSICVIDEO_USER_RATING; + varindex = DatabaseUtils::GetFieldIndex(FieldUserRating, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MUSICVIDEO_PREMIERED; + varindex = DatabaseUtils::GetFieldIndex(FieldYear, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); + + refindex = -1; + varindex = DatabaseUtils::GetFieldIndex(FieldRandom, MediaTypeMusicVideo); + EXPECT_EQ(refindex, varindex); +} + +TEST(TestDatabaseUtils, GetFieldIndex_MediaTypeMovie) +{ + int refindex, varindex; + + refindex = 0; + varindex = DatabaseUtils::GetFieldIndex(FieldId, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TITLE + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldTitle, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_SORTTITLE + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldSortTitle, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_PLOT + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldPlot, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_PLOTOUTLINE + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldPlotOutline, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TAGLINE + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldTagline, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_CREDITS + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldWriter, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_RUNTIME + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldTime, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_MPAA + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldMPAA, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TOP250 + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldTop250, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_GENRE + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldGenre, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_DIRECTOR + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldDirector, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_STUDIOS + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldStudio, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TRAILER + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldTrailer, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_COUNTRY + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldCountry, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MOVIE_FILE + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldFilename, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MOVIE_PATH; + varindex = DatabaseUtils::GetFieldIndex(FieldPath, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MOVIE_PLAYCOUNT; + varindex = DatabaseUtils::GetFieldIndex(FieldPlaycount, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MOVIE_LASTPLAYED; + varindex = DatabaseUtils::GetFieldIndex(FieldLastPlayed, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MOVIE_DATEADDED; + varindex = DatabaseUtils::GetFieldIndex(FieldDateAdded, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MOVIE_USER_RATING; + varindex = DatabaseUtils::GetFieldIndex(FieldUserRating, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MOVIE_VOTES; + varindex = DatabaseUtils::GetFieldIndex(FieldVotes, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MOVIE_RATING; + varindex = DatabaseUtils::GetFieldIndex(FieldRating, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_MOVIE_PREMIERED; + varindex = DatabaseUtils::GetFieldIndex(FieldYear, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); + + refindex = -1; + varindex = DatabaseUtils::GetFieldIndex(FieldRandom, MediaTypeMovie); + EXPECT_EQ(refindex, varindex); +} + +TEST(TestDatabaseUtils, GetFieldIndex_MediaTypeTvShow) +{ + int refindex, varindex; + + refindex = 0; + varindex = DatabaseUtils::GetFieldIndex(FieldId, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TV_TITLE + 1; + varindex = DatabaseUtils::GetFieldIndex(FieldTitle, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TV_SORTTITLE + 1; + varindex = DatabaseUtils::GetFieldIndex(FieldSortTitle, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TV_PLOT + 1; + varindex = DatabaseUtils::GetFieldIndex(FieldPlot, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TV_STATUS + 1; + varindex = DatabaseUtils::GetFieldIndex(FieldTvShowStatus, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TV_PREMIERED + 1; + varindex = DatabaseUtils::GetFieldIndex(FieldYear, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TV_GENRE + 1; + varindex = DatabaseUtils::GetFieldIndex(FieldGenre, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TV_MPAA + 1; + varindex = DatabaseUtils::GetFieldIndex(FieldMPAA, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_TV_STUDIOS + 1; + varindex = DatabaseUtils::GetFieldIndex(FieldStudio, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_TVSHOW_PATH; + varindex = DatabaseUtils::GetFieldIndex(FieldPath, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_TVSHOW_DATEADDED; + varindex = DatabaseUtils::GetFieldIndex(FieldDateAdded, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_TVSHOW_NUM_EPISODES; + varindex = DatabaseUtils::GetFieldIndex(FieldNumberOfEpisodes, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_TVSHOW_NUM_WATCHED; + varindex = DatabaseUtils::GetFieldIndex(FieldNumberOfWatchedEpisodes, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_TVSHOW_NUM_SEASONS; + varindex = DatabaseUtils::GetFieldIndex(FieldSeason, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_TVSHOW_USER_RATING; + varindex = DatabaseUtils::GetFieldIndex(FieldUserRating, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_TVSHOW_VOTES; + varindex = DatabaseUtils::GetFieldIndex(FieldVotes, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_TVSHOW_RATING; + varindex = DatabaseUtils::GetFieldIndex(FieldRating, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); + + refindex = -1; + varindex = DatabaseUtils::GetFieldIndex(FieldRandom, MediaTypeTvShow); + EXPECT_EQ(refindex, varindex); +} + +TEST(TestDatabaseUtils, GetFieldIndex_MediaTypeEpisode) +{ + int refindex, varindex; + + refindex = 0; + varindex = DatabaseUtils::GetFieldIndex(FieldId, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_EPISODE_TITLE + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldTitle, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_EPISODE_PLOT + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldPlot, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_EPISODE_CREDITS + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldWriter, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_EPISODE_AIRED + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldAirDate, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_EPISODE_RUNTIME + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldTime, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_EPISODE_DIRECTOR + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldDirector, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_EPISODE_SEASON + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldSeason, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_ID_EPISODE_EPISODE + 2; + varindex = DatabaseUtils::GetFieldIndex(FieldEpisodeNumber, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_FILE; + varindex = DatabaseUtils::GetFieldIndex(FieldFilename, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_PATH; + varindex = DatabaseUtils::GetFieldIndex(FieldPath, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_PLAYCOUNT; + varindex = DatabaseUtils::GetFieldIndex(FieldPlaycount, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_LASTPLAYED; + varindex = DatabaseUtils::GetFieldIndex(FieldLastPlayed, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_DATEADDED; + varindex = DatabaseUtils::GetFieldIndex(FieldDateAdded, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_TVSHOW_NAME; + varindex = DatabaseUtils::GetFieldIndex(FieldTvShowTitle, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_TVSHOW_STUDIO; + varindex = DatabaseUtils::GetFieldIndex(FieldStudio, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_TVSHOW_AIRED; + varindex = DatabaseUtils::GetFieldIndex(FieldYear, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_TVSHOW_MPAA; + varindex = DatabaseUtils::GetFieldIndex(FieldMPAA, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_USER_RATING; + varindex = DatabaseUtils::GetFieldIndex(FieldUserRating, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_VOTES; + varindex = DatabaseUtils::GetFieldIndex(FieldVotes, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = VIDEODB_DETAILS_EPISODE_RATING; + varindex = DatabaseUtils::GetFieldIndex(FieldRating, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); + + refindex = -1; + varindex = DatabaseUtils::GetFieldIndex(FieldRandom, MediaTypeEpisode); + EXPECT_EQ(refindex, varindex); +} + +TEST(TestDatabaseUtils, GetSelectFields) +{ + Fields fields; + FieldList fieldlist; + + EXPECT_FALSE(DatabaseUtils::GetSelectFields(fields, MediaTypeAlbum, + fieldlist)); + + fields.insert(FieldId); + fields.insert(FieldGenre); + fields.insert(FieldAlbum); + fields.insert(FieldArtist); + fields.insert(FieldTitle); + EXPECT_FALSE(DatabaseUtils::GetSelectFields(fields, MediaTypeNone, + fieldlist)); + EXPECT_TRUE(DatabaseUtils::GetSelectFields(fields, MediaTypeAlbum, + fieldlist)); + EXPECT_FALSE(fieldlist.empty()); +} + +TEST(TestDatabaseUtils, GetFieldValue) +{ + CVariant v_null, v_string; + dbiplus::field_value f_null, f_string("test"); + + f_null.set_isNull(); + EXPECT_TRUE(DatabaseUtils::GetFieldValue(f_null, v_null)); + EXPECT_TRUE(v_null.isNull()); + + EXPECT_TRUE(DatabaseUtils::GetFieldValue(f_string, v_string)); + EXPECT_FALSE(v_string.isNull()); + EXPECT_TRUE(v_string.isString()); +} + +//! @todo Need some way to test this function +// TEST(TestDatabaseUtils, GetDatabaseResults) +// { +// static bool GetDatabaseResults(MediaType mediaType, const FieldList &fields, +// const std::unique_ptr<dbiplus::Dataset> &dataset, +// DatabaseResults &results); +// } + +TEST(TestDatabaseUtils, BuildLimitClause) +{ + std::string a = DatabaseUtils::BuildLimitClause(100); + EXPECT_STREQ(" LIMIT 100", a.c_str()); +} + +// class DatabaseUtils +// { +// public: +// +// +// static std::string BuildLimitClause(int end, int start = 0); +// }; diff --git a/xbmc/utils/test/TestDigest.cpp b/xbmc/utils/test/TestDigest.cpp new file mode 100644 index 0000000..96d0529 --- /dev/null +++ b/xbmc/utils/test/TestDigest.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/Digest.h" + +#include <gtest/gtest.h> + +using KODI::UTILITY::CDigest; +using KODI::UTILITY::TypedDigest; + +TEST(TestDigest, Digest_Empty) +{ + EXPECT_STREQ(CDigest::Calculate(CDigest::Type::MD5, "").c_str(), "d41d8cd98f00b204e9800998ecf8427e"); + EXPECT_STREQ(CDigest::Calculate(CDigest::Type::MD5, nullptr, 0).c_str(), "d41d8cd98f00b204e9800998ecf8427e"); + { + CDigest digest{CDigest::Type::MD5}; + EXPECT_STREQ(digest.Finalize().c_str(), "d41d8cd98f00b204e9800998ecf8427e"); + } + { + CDigest digest{CDigest::Type::MD5}; + digest.Update(""); + digest.Update(nullptr, 0); + EXPECT_STREQ(digest.Finalize().c_str(), "d41d8cd98f00b204e9800998ecf8427e"); + } +} + +TEST(TestDigest, Digest_Basic) +{ + EXPECT_STREQ(CDigest::Calculate(CDigest::Type::MD5, "asdf").c_str(), "912ec803b2ce49e4a541068d495ab570"); + EXPECT_STREQ(CDigest::Calculate(CDigest::Type::MD5, "asdf", 4).c_str(), "912ec803b2ce49e4a541068d495ab570"); + { + CDigest digest{CDigest::Type::MD5}; + digest.Update("as"); + digest.Update("df", 2); + EXPECT_STREQ(digest.Finalize().c_str(), "912ec803b2ce49e4a541068d495ab570"); + } +} + +TEST(TestDigest, Digest_SHA1) +{ + EXPECT_STREQ(CDigest::Calculate(CDigest::Type::SHA1, "").c_str(), "da39a3ee5e6b4b0d3255bfef95601890afd80709"); + EXPECT_STREQ(CDigest::Calculate(CDigest::Type::SHA1, "asdf").c_str(), "3da541559918a808c2402bba5012f6c60b27661c"); +} + +TEST(TestDigest, Digest_SHA256) +{ + EXPECT_STREQ(CDigest::Calculate(CDigest::Type::SHA256, "").c_str(), "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + EXPECT_STREQ(CDigest::Calculate(CDigest::Type::SHA256, "asdf").c_str(), "f0e4c2f76c58916ec258f246851bea091d14d4247a2fc3e18694461b1816e13b"); +} + +TEST(TestDigest, Digest_SHA512) +{ + EXPECT_STREQ(CDigest::Calculate(CDigest::Type::SHA512, "").c_str(), "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e"); + EXPECT_STREQ(CDigest::Calculate(CDigest::Type::SHA512, "asdf").c_str(), "401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429080fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1"); +} + +TEST(TestDigest, TypedDigest_Empty) +{ + TypedDigest t1, t2; + EXPECT_EQ(t1, t2); + EXPECT_EQ(t1.type, CDigest::Type::INVALID); + EXPECT_EQ(t1.value, ""); + EXPECT_TRUE(t1.Empty()); + t1.type = CDigest::Type::SHA1; + EXPECT_TRUE(t1.Empty()); +} + +TEST(TestDigest, TypedDigest_SameType) +{ + TypedDigest t1{CDigest::Type::SHA1, "da39a3ee5e6b4b0d3255bfef95601890afd80709"}; + TypedDigest t2{CDigest::Type::SHA1, "da39a3ee5e6b4b0d3255bfef95601890afd80708"}; + EXPECT_NE(t1, t2); + EXPECT_FALSE(t1.Empty()); +} + +TEST(TestDigest, TypedDigest_CompareCase) +{ + TypedDigest t1{CDigest::Type::SHA1, "da39a3ee5e6b4b0d3255bfef95601890afd80708"}; + TypedDigest t2{CDigest::Type::SHA1, "da39A3EE5e6b4b0d3255bfef95601890afd80708"}; + EXPECT_EQ(t1, t2); +} + +TEST(TestDigest, TypedDigest_DifferingType) +{ + TypedDigest t1{CDigest::Type::SHA1, "da39a3ee5e6b4b0d3255bfef95601890afd80709"}; + TypedDigest t2{CDigest::Type::SHA256, "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"}; + // Silence "unused expression" warning + bool a; + EXPECT_THROW(a = (t1 == t2), std::logic_error); + // Silence "unused variable" warning + (void)a; + EXPECT_THROW(a = (t1 != t2), std::logic_error); + (void)a; +} diff --git a/xbmc/utils/test/TestEndianSwap.cpp b/xbmc/utils/test/TestEndianSwap.cpp new file mode 100644 index 0000000..70d3cf0 --- /dev/null +++ b/xbmc/utils/test/TestEndianSwap.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/EndianSwap.h" + +#include <gtest/gtest.h> + +TEST(TestEndianSwap, Endian_Swap16) +{ + uint16_t ref, var; + ref = 0x00FF; + var = Endian_Swap16(0xFF00); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_Swap32) +{ + uint32_t ref, var; + ref = 0x00FF00FF; + var = Endian_Swap32(0xFF00FF00); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_Swap64) +{ + uint64_t ref, var; + ref = UINT64_C(0x00FF00FF00FF00FF); + var = Endian_Swap64(UINT64_C(0xFF00FF00FF00FF00)); + EXPECT_EQ(ref, var); +} + +#ifndef WORDS_BIGENDIAN +TEST(TestEndianSwap, Endian_SwapLE16) +{ + uint16_t ref, var; + ref = 0x00FF; + var = Endian_SwapLE16(0x00FF); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_SwapLE32) +{ + uint32_t ref, var; + ref = 0x00FF00FF; + var = Endian_SwapLE32(0x00FF00FF); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_SwapLE64) +{ + uint64_t ref, var; + ref = UINT64_C(0x00FF00FF00FF00FF); + var = Endian_SwapLE64(UINT64_C(0x00FF00FF00FF00FF)); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_SwapBE16) +{ + uint16_t ref, var; + ref = 0x00FF; + var = Endian_SwapBE16(0xFF00); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_SwapBE32) +{ + uint32_t ref, var; + ref = 0x00FF00FF; + var = Endian_SwapBE32(0xFF00FF00); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_SwapBE64) +{ + uint64_t ref, var; + ref = UINT64_C(0x00FF00FF00FF00FF); + var = Endian_SwapBE64(UINT64_C(0xFF00FF00FF00FF00)); + EXPECT_EQ(ref, var); +} +#else +TEST(TestEndianSwap, Endian_SwapLE16) +{ + uint16_t ref, var; + ref = 0x00FF; + var = Endian_SwapLE16(0xFF00); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_SwapLE32) +{ + uint32_t ref, var; + ref = 0x00FF00FF; + var = Endian_SwapLE32(0xFF00FF00); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_SwapLE64) +{ + uint64_t ref, var; + ref = UINT64_C(0x00FF00FF00FF00FF); + var = Endian_SwapLE64(UINT64_C(0xFF00FF00FF00FF00)); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_SwapBE16) +{ + uint16_t ref, var; + ref = 0x00FF; + var = Endian_SwapBE16(0x00FF); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_SwapBE32) +{ + uint32_t ref, var; + ref = 0x00FF00FF; + var = Endian_SwapBE32(0x00FF00FF); + EXPECT_EQ(ref, var); +} + +TEST(TestEndianSwap, Endian_SwapBE64) +{ + uint64_t ref, var; + ref = UINT64_C(0x00FF00FF00FF00FF); + var = Endian_SwapBE64(UINT64_C(0x00FF00FF00FF00FF)); + EXPECT_EQ(ref, var); +} +#endif diff --git a/xbmc/utils/test/TestExecString.cpp b/xbmc/utils/test/TestExecString.cpp new file mode 100644 index 0000000..4577b87 --- /dev/null +++ b/xbmc/utils/test/TestExecString.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2022 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "FileItem.h" +#include "utils/ExecString.h" + +#include <gtest/gtest.h> + +TEST(TestExecString, ctor_1) +{ + { + const CExecString exec("ActivateWindow(Video, \"C:\\test\\foo\")"); + EXPECT_EQ(exec.IsValid(), true); + EXPECT_EQ(exec.GetFunction(), "activatewindow"); + EXPECT_EQ(exec.GetParams().size(), 2U); + EXPECT_EQ(exec.GetParams()[0], "Video"); + EXPECT_EQ(exec.GetParams()[1], "C:\\test\\foo"); + EXPECT_EQ(exec.GetExecString(), "ActivateWindow(Video, \"C:\\test\\foo\")"); + } + { + const CExecString exec("ActivateWindow(Video, \"C:\\test\\foo\\\")"); + EXPECT_EQ(exec.IsValid(), true); + EXPECT_EQ(exec.GetFunction(), "activatewindow"); + EXPECT_EQ(exec.GetParams().size(), 2U); + EXPECT_EQ(exec.GetParams()[0], "Video"); + EXPECT_EQ(exec.GetParams()[1], "C:\\test\\foo"); + EXPECT_EQ(exec.GetExecString(), "ActivateWindow(Video, \"C:\\test\\foo\\\")"); + } + { + const CExecString exec("ActivateWindow(Video, \"C:\\\\test\\\\foo\\\\\")"); + EXPECT_EQ(exec.IsValid(), true); + EXPECT_EQ(exec.GetFunction(), "activatewindow"); + EXPECT_EQ(exec.GetParams().size(), 2U); + EXPECT_EQ(exec.GetParams()[0], "Video"); + EXPECT_EQ(exec.GetParams()[1], "C:\\test\\foo\\"); + EXPECT_EQ(exec.GetExecString(), "ActivateWindow(Video, \"C:\\\\test\\\\foo\\\\\")"); + } + { + const CExecString exec("ActivateWindow(Video, \"C:\\\\\\\\test\\\\\\foo\\\\\")"); + EXPECT_EQ(exec.IsValid(), true); + EXPECT_EQ(exec.GetFunction(), "activatewindow"); + EXPECT_EQ(exec.GetParams().size(), 2U); + EXPECT_EQ(exec.GetParams()[0], "Video"); + EXPECT_EQ(exec.GetParams()[1], "C:\\\\test\\\\foo\\"); + EXPECT_EQ(exec.GetExecString(), "ActivateWindow(Video, \"C:\\\\\\\\test\\\\\\foo\\\\\")"); + } + { + const CExecString exec("SetProperty(Foo,\"\")"); + EXPECT_EQ(exec.IsValid(), true); + EXPECT_EQ(exec.GetFunction(), "setproperty"); + EXPECT_EQ(exec.GetParams().size(), 2U); + EXPECT_EQ(exec.GetParams()[0], "Foo"); + EXPECT_EQ(exec.GetParams()[1], ""); + EXPECT_EQ(exec.GetExecString(), "SetProperty(Foo,\"\")"); + } + { + const CExecString exec("SetProperty(foo,ba(\"ba black )\",sheep))"); + EXPECT_EQ(exec.IsValid(), true); + EXPECT_EQ(exec.GetFunction(), "setproperty"); + EXPECT_EQ(exec.GetParams().size(), 2U); + EXPECT_EQ(exec.GetParams()[0], "foo"); + EXPECT_EQ(exec.GetParams()[1], "ba(\"ba black )\",sheep)"); + EXPECT_EQ(exec.GetExecString(), "SetProperty(foo,ba(\"ba black )\",sheep))"); + } +} + +TEST(TestExecString, ctor_2) +{ + { + const CExecString exec("ActivateWindow", {"Video", "C:\\test\\foo"}); + EXPECT_EQ(exec.IsValid(), true); + EXPECT_EQ(exec.GetFunction(), "activatewindow"); + EXPECT_EQ(exec.GetParams().size(), 2U); + EXPECT_EQ(exec.GetParams()[0], "Video"); + EXPECT_EQ(exec.GetParams()[1], "C:\\test\\foo"); + EXPECT_EQ(exec.GetExecString(), "ActivateWindow(Video,C:\\test\\foo)"); + } +} + +TEST(TestExecString, ctor_3) +{ + { + const CFileItem item("C:\\test\\foo", true); + const CExecString exec(item, "Video"); + EXPECT_EQ(exec.IsValid(), true); + EXPECT_EQ(exec.GetFunction(), "activatewindow"); + EXPECT_EQ(exec.GetParams().size(), 3U); + EXPECT_EQ(exec.GetParams()[0], "Video"); + EXPECT_EQ(exec.GetParams()[1], "\"C:\\\\test\\\\foo\\\\\""); + EXPECT_EQ(exec.GetParams()[2], "return"); + EXPECT_EQ(exec.GetExecString(), "ActivateWindow(Video,\"C:\\\\test\\\\foo\\\\\",return)"); + } + { + const CFileItem item("C:\\test\\foo\\", true); + const CExecString exec(item, "Video"); + EXPECT_EQ(exec.IsValid(), true); + EXPECT_EQ(exec.GetFunction(), "activatewindow"); + EXPECT_EQ(exec.GetParams().size(), 3U); + EXPECT_EQ(exec.GetParams()[0], "Video"); + EXPECT_EQ(exec.GetParams()[1], "\"C:\\\\test\\\\foo\\\\\""); + EXPECT_EQ(exec.GetParams()[2], "return"); + EXPECT_EQ(exec.GetExecString(), "ActivateWindow(Video,\"C:\\\\test\\\\foo\\\\\",return)"); + } + { + const CFileItem item("C:\\test\\foo", false); + const CExecString exec(item, "Video"); + EXPECT_EQ(exec.IsValid(), true); + EXPECT_EQ(exec.GetFunction(), "playmedia"); + EXPECT_EQ(exec.GetParams().size(), 1U); + EXPECT_EQ(exec.GetParams()[0], "\"C:\\\\test\\\\foo\""); + EXPECT_EQ(exec.GetExecString(), "PlayMedia(\"C:\\\\test\\\\foo\")"); + } +} diff --git a/xbmc/utils/test/TestFileOperationJob.cpp b/xbmc/utils/test/TestFileOperationJob.cpp new file mode 100644 index 0000000..1df243e --- /dev/null +++ b/xbmc/utils/test/TestFileOperationJob.cpp @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "filesystem/Directory.h" +#include "filesystem/File.h" +#include "test/TestUtils.h" +#include "utils/FileOperationJob.h" +#include "utils/URIUtils.h" + +#include <gtest/gtest.h> + +TEST(TestFileOperationJob, ActionCopy) +{ + XFILE::CFile *tmpfile; + std::string tmpfilepath, destfile; + CFileItemList items; + CFileOperationJob job; + + ASSERT_NE(nullptr, (tmpfile = XBMC_CREATETEMPFILE(""))); + tmpfilepath = XBMC_TEMPFILEPATH(tmpfile); + tmpfile->Close(); + + CFileItemPtr item(new CFileItem(tmpfilepath)); + item->SetPath(tmpfilepath); + item->m_bIsFolder = false; + item->Select(true); + items.Add(item); + + std::string destpath = URIUtils::GetDirectory(tmpfilepath); + destpath = URIUtils::AddFileToFolder(destpath, "copy"); + destfile = URIUtils::AddFileToFolder(destpath, URIUtils::GetFileName(tmpfilepath)); + ASSERT_FALSE(XFILE::CFile::Exists(destfile)); + + job.SetFileOperation(CFileOperationJob::ActionCopy, items, destpath); + EXPECT_EQ(CFileOperationJob::ActionCopy, job.GetAction()); + + EXPECT_TRUE(job.DoWork()); + EXPECT_TRUE(XFILE::CFile::Exists(tmpfilepath)); + EXPECT_TRUE(XFILE::CFile::Exists(destfile)); + + EXPECT_TRUE(XBMC_DELETETEMPFILE(tmpfile)); + EXPECT_TRUE(XFILE::CFile::Delete(destfile)); + EXPECT_TRUE(XFILE::CDirectory::Remove(destpath)); +} + +TEST(TestFileOperationJob, ActionMove) +{ + XFILE::CFile *tmpfile; + std::string tmpfilepath, destfile; + CFileItemList items; + CFileOperationJob job; + + ASSERT_NE(nullptr, (tmpfile = XBMC_CREATETEMPFILE(""))); + tmpfilepath = XBMC_TEMPFILEPATH(tmpfile); + tmpfile->Close(); + + CFileItemPtr item(new CFileItem(tmpfilepath)); + item->SetPath(tmpfilepath); + item->m_bIsFolder = false; + item->Select(true); + items.Add(item); + + std::string destpath = URIUtils::GetDirectory(tmpfilepath); + destpath = URIUtils::AddFileToFolder(destpath, "move"); + destfile = URIUtils::AddFileToFolder(destpath, URIUtils::GetFileName(tmpfilepath)); + ASSERT_FALSE(XFILE::CFile::Exists(destfile)); + ASSERT_TRUE(XFILE::CDirectory::Create(destpath)); + + job.SetFileOperation(CFileOperationJob::ActionMove, items, destpath); + EXPECT_EQ(CFileOperationJob::ActionMove, job.GetAction()); + + EXPECT_TRUE(job.DoWork()); + EXPECT_FALSE(XFILE::CFile::Exists(tmpfilepath)); + EXPECT_TRUE(XFILE::CFile::Exists(destfile)); + + EXPECT_TRUE(XFILE::CFile::Delete(destfile)); + EXPECT_TRUE(XFILE::CDirectory::Remove(destpath)); + + EXPECT_FALSE(XBMC_DELETETEMPFILE(tmpfile)); +} + +TEST(TestFileOperationJob, ActionDelete) +{ + XFILE::CFile *tmpfile; + std::string tmpfilepath, destfile; + CFileItemList items; + CFileOperationJob job; + + ASSERT_NE(nullptr, (tmpfile = XBMC_CREATETEMPFILE(""))); + tmpfilepath = XBMC_TEMPFILEPATH(tmpfile); + tmpfile->Close(); + + CFileItemPtr item(new CFileItem(tmpfilepath)); + item->SetPath(tmpfilepath); + item->m_bIsFolder = false; + item->Select(true); + items.Add(item); + + std::string destpath = URIUtils::GetDirectory(tmpfilepath); + destpath = URIUtils::AddFileToFolder(destpath, "delete"); + destfile = URIUtils::AddFileToFolder(destpath, URIUtils::GetFileName(tmpfilepath)); + ASSERT_FALSE(XFILE::CFile::Exists(destfile)); + + job.SetFileOperation(CFileOperationJob::ActionCopy, items, destpath); + EXPECT_EQ(CFileOperationJob::ActionCopy, job.GetAction()); + + EXPECT_TRUE(job.DoWork()); + EXPECT_TRUE(XFILE::CFile::Exists(tmpfilepath)); + EXPECT_TRUE(XFILE::CFile::Exists(destfile)); + + job.SetFileOperation(CFileOperationJob::ActionDelete, items, ""); + EXPECT_EQ(CFileOperationJob::ActionDelete, job.GetAction()); + + EXPECT_TRUE(job.DoWork()); + EXPECT_FALSE(XFILE::CFile::Exists(tmpfilepath)); + + items.Clear(); + CFileItemPtr item2(new CFileItem(destfile)); + item2->SetPath(destfile); + item2->m_bIsFolder = false; + item2->Select(true); + items.Add(item2); + + job.SetFileOperation(CFileOperationJob::ActionDelete, items, ""); + EXPECT_EQ(CFileOperationJob::ActionDelete, job.GetAction()); + + EXPECT_TRUE(job.DoWork()); + EXPECT_FALSE(XFILE::CFile::Exists(destfile)); + EXPECT_TRUE(XFILE::CDirectory::Remove(destpath)); + + EXPECT_FALSE(XBMC_DELETETEMPFILE(tmpfile)); +} + +TEST(TestFileOperationJob, ActionReplace) +{ + XFILE::CFile *tmpfile; + std::string tmpfilepath, destfile; + CFileItemList items; + CFileOperationJob job; + + ASSERT_NE(nullptr, (tmpfile = XBMC_CREATETEMPFILE(""))); + tmpfilepath = XBMC_TEMPFILEPATH(tmpfile); + tmpfile->Close(); + + CFileItemPtr item(new CFileItem(tmpfilepath)); + item->SetPath(tmpfilepath); + item->m_bIsFolder = false; + item->Select(true); + items.Add(item); + + std::string destpath = URIUtils::GetDirectory(tmpfilepath); + destpath = URIUtils::AddFileToFolder(destpath, "replace"); + destfile = URIUtils::AddFileToFolder(destpath, URIUtils::GetFileName(tmpfilepath)); + ASSERT_FALSE(XFILE::CFile::Exists(destfile)); + + job.SetFileOperation(CFileOperationJob::ActionCopy, items, destpath); + EXPECT_EQ(CFileOperationJob::ActionCopy, job.GetAction()); + + EXPECT_TRUE(job.DoWork()); + EXPECT_TRUE(XFILE::CFile::Exists(tmpfilepath)); + EXPECT_TRUE(XFILE::CFile::Exists(destfile)); + + job.SetFileOperation(CFileOperationJob::ActionReplace, items, destpath); + EXPECT_EQ(CFileOperationJob::ActionReplace, job.GetAction()); + + EXPECT_TRUE(job.DoWork()); + EXPECT_TRUE(XFILE::CFile::Exists(destfile)); + + EXPECT_TRUE(XBMC_DELETETEMPFILE(tmpfile)); + EXPECT_TRUE(XFILE::CFile::Delete(destfile)); + EXPECT_TRUE(XFILE::CDirectory::Remove(destpath)); +} + +TEST(TestFileOperationJob, ActionCreateFolder) +{ + XFILE::CFile *tmpfile; + std::string tmpfilepath, destpath; + CFileItemList items; + CFileOperationJob job; + + ASSERT_NE(nullptr, (tmpfile = XBMC_CREATETEMPFILE(""))); + tmpfilepath = XBMC_TEMPFILEPATH(tmpfile); + + std::string tmpfiledirectory = + CXBMCTestUtils::Instance().TempFileDirectory(tmpfile); + + tmpfile->Close(); + + destpath = tmpfilepath; + destpath += ".createfolder"; + ASSERT_FALSE(XFILE::CFile::Exists(destpath)); + + CFileItemPtr item(new CFileItem(destpath)); + item->SetPath(destpath); + item->m_bIsFolder = true; + item->Select(true); + items.Add(item); + + job.SetFileOperation(CFileOperationJob::ActionCreateFolder, items, tmpfiledirectory); + EXPECT_EQ(CFileOperationJob::ActionCreateFolder, job.GetAction()); + + EXPECT_TRUE(job.DoWork()); + EXPECT_TRUE(XFILE::CDirectory::Exists(destpath)); + + EXPECT_TRUE(XBMC_DELETETEMPFILE(tmpfile)); + EXPECT_TRUE(XFILE::CDirectory::Remove(destpath)); +} + +// This test will fail until ActionDeleteFolder has a proper implementation +TEST(TestFileOperationJob, ActionDeleteFolder) +{ + XFILE::CFile *tmpfile; + std::string tmpfilepath, destpath; + CFileItemList items; + CFileOperationJob job; + + ASSERT_NE(nullptr, (tmpfile = XBMC_CREATETEMPFILE(""))); + tmpfilepath = XBMC_TEMPFILEPATH(tmpfile); + + std::string tmpfiledirectory = + CXBMCTestUtils::Instance().TempFileDirectory(tmpfile); + + tmpfile->Close(); + + destpath = tmpfilepath; + destpath += ".deletefolder"; + ASSERT_FALSE(XFILE::CFile::Exists(destpath)); + + CFileItemPtr item(new CFileItem(destpath)); + item->SetPath(destpath); + item->m_bIsFolder = true; + item->Select(true); + items.Add(item); + + job.SetFileOperation(CFileOperationJob::ActionCreateFolder, items, tmpfiledirectory); + EXPECT_EQ(CFileOperationJob::ActionCreateFolder, job.GetAction()); + + EXPECT_TRUE(job.DoWork()); + EXPECT_TRUE(XFILE::CDirectory::Exists(destpath)); + + job.SetFileOperation(CFileOperationJob::ActionDeleteFolder, items, tmpfiledirectory); + EXPECT_EQ(CFileOperationJob::ActionDeleteFolder, job.GetAction()); + + EXPECT_TRUE(job.DoWork()); + EXPECT_FALSE(XFILE::CDirectory::Exists(destpath)); + + EXPECT_TRUE(XBMC_DELETETEMPFILE(tmpfile)); +} + +TEST(TestFileOperationJob, GetFunctions) +{ + XFILE::CFile *tmpfile; + std::string tmpfilepath, destfile; + CFileItemList items; + CFileOperationJob job; + + ASSERT_NE(nullptr, (tmpfile = XBMC_CREATETEMPFILE(""))); + tmpfilepath = XBMC_TEMPFILEPATH(tmpfile); + tmpfile->Close(); + + CFileItemPtr item(new CFileItem(tmpfilepath)); + item->SetPath(tmpfilepath); + item->m_bIsFolder = false; + item->Select(true); + items.Add(item); + + std::string destpath = URIUtils::GetDirectory(tmpfilepath); + destpath = URIUtils::AddFileToFolder(destpath, "getfunctions"); + destfile = URIUtils::AddFileToFolder(destpath, URIUtils::GetFileName(tmpfilepath)); + ASSERT_FALSE(XFILE::CFile::Exists(destfile)); + + job.SetFileOperation(CFileOperationJob::ActionCopy, items, destpath); + EXPECT_EQ(CFileOperationJob::ActionCopy, job.GetAction()); + + EXPECT_TRUE(job.DoWork()); + EXPECT_TRUE(XFILE::CFile::Exists(tmpfilepath)); + EXPECT_TRUE(XFILE::CFile::Exists(destfile)); + + std::cout << "GetAverageSpeed(): " << job.GetAverageSpeed() << std::endl; + std::cout << "GetCurrentOperation(): " << job.GetCurrentOperation() << std::endl; + std::cout << "GetCurrentFile(): " << job.GetCurrentFile() << std::endl; + EXPECT_FALSE(job.GetItems().IsEmpty()); + + EXPECT_TRUE(XBMC_DELETETEMPFILE(tmpfile)); + EXPECT_TRUE(XFILE::CFile::Delete(destfile)); + EXPECT_TRUE(XFILE::CDirectory::Remove(destpath)); +} diff --git a/xbmc/utils/test/TestFileUtils.cpp b/xbmc/utils/test/TestFileUtils.cpp new file mode 100644 index 0000000..bb9b8b6 --- /dev/null +++ b/xbmc/utils/test/TestFileUtils.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "FileItem.h" +#include "filesystem/File.h" +#include "test/TestUtils.h" +#include "utils/FileUtils.h" + +#include <gtest/gtest.h> + +TEST(TestFileUtils, DeleteItem_CFileItemPtr) +{ + XFILE::CFile *tmpfile; + std::string tmpfilepath; + + ASSERT_NE(nullptr, (tmpfile = XBMC_CREATETEMPFILE(""))); + tmpfilepath = XBMC_TEMPFILEPATH(tmpfile); + + CFileItemPtr item(new CFileItem(tmpfilepath)); + item->SetPath(tmpfilepath); + item->m_bIsFolder = false; + item->Select(true); + tmpfile->Close(); //Close tmpfile before we try to delete it + EXPECT_TRUE(CFileUtils::DeleteItem(item)); + EXPECT_FALSE(XBMC_DELETETEMPFILE(tmpfile)); +} + +TEST(TestFileUtils, DeleteItemString) +{ + XFILE::CFile *tmpfile; + + ASSERT_NE(nullptr, (tmpfile = XBMC_CREATETEMPFILE(""))); + tmpfile->Close(); //Close tmpfile before we try to delete it + EXPECT_TRUE(CFileUtils::DeleteItem(XBMC_TEMPFILEPATH(tmpfile))); + EXPECT_FALSE(XBMC_DELETETEMPFILE(tmpfile)); +} + +/* Executing RenameFile() requires input from the user */ +// static bool RenameFile(const std::string &strFile); diff --git a/xbmc/utils/test/TestGlobalsHandling.cpp b/xbmc/utils/test/TestGlobalsHandling.cpp new file mode 100644 index 0000000..5b8d26a --- /dev/null +++ b/xbmc/utils/test/TestGlobalsHandling.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/test/TestGlobalsHandlingPattern1.h" + +#include <gtest/gtest.h> + +using namespace xbmcutil; +using namespace test; + +bool TestGlobalPattern1::ctorCalled = false; +bool TestGlobalPattern1::dtorCalled = false; + +TEST(TestGlobal, Pattern1) +{ + EXPECT_TRUE(TestGlobalPattern1::ctorCalled); + { + std::shared_ptr<TestGlobalPattern1> ptr = g_testGlobalPattern1Ref; + } +} diff --git a/xbmc/utils/test/TestGlobalsHandlingPattern1.h b/xbmc/utils/test/TestGlobalsHandlingPattern1.h new file mode 100644 index 0000000..92088b8 --- /dev/null +++ b/xbmc/utils/test/TestGlobalsHandlingPattern1.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "utils/GlobalsHandling.h" + +#include <iostream> + +namespace xbmcutil +{ + namespace test + { + class TestGlobalPattern1 + { + public: + static bool ctorCalled; + static bool dtorCalled; + + int somethingToAccess = 0; + + TestGlobalPattern1() { ctorCalled = true; } + ~TestGlobalPattern1() + { + std::cout << "Clean shutdown of TestGlobalPattern1" << std::endl << std::flush; + dtorCalled = true; + } + + void beHappy() { if (somethingToAccess) throw somethingToAccess; } + }; + } +} + +XBMC_GLOBAL_REF(xbmcutil::test::TestGlobalPattern1,g_testGlobalPattern1); +#define g_testGlobalPattern1 XBMC_GLOBAL_USE(xbmcutil::test::TestGlobalPattern1) diff --git a/xbmc/utils/test/TestHTMLUtil.cpp b/xbmc/utils/test/TestHTMLUtil.cpp new file mode 100644 index 0000000..7d0e515 --- /dev/null +++ b/xbmc/utils/test/TestHTMLUtil.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/HTMLUtil.h" + +#include <gtest/gtest.h> + +TEST(TestHTMLUtil, RemoveTags) +{ + std::string str; + str = "<!DOCTYPE html>\n" + "<html>\n" + " <head class=\"someclass\">\n" + " <body>\n" + " <p>blah blah blah</p>\n" + " </body>\n" + " </head>\n" + "</html>\n"; + HTML::CHTMLUtil::RemoveTags(str); + EXPECT_STREQ("\n\n \n \n blah blah blah\n \n \n\n", + str.c_str()); +} + +TEST(TestHTMLUtil, ConvertHTMLToW) +{ + std::wstring inw, refstrw, varstrw; + inw = L"å&€"; + refstrw = L"\u00e5&\u20ac"; + HTML::CHTMLUtil::ConvertHTMLToW(inw, varstrw); + EXPECT_STREQ(refstrw.c_str(), varstrw.c_str()); +} diff --git a/xbmc/utils/test/TestHttpHeader.cpp b/xbmc/utils/test/TestHttpHeader.cpp new file mode 100644 index 0000000..1aeecc7 --- /dev/null +++ b/xbmc/utils/test/TestHttpHeader.cpp @@ -0,0 +1,505 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/HttpHeader.h" + +#include <string.h> + +#include <gtest/gtest.h> + +#define CHECK_CNT_TYPE_NAME "Content-Type" +#define CHECK_CONTENT_TYPE_HTML "text/html" +#define CHECK_CONTENT_TYPE_HTML_CHRS "text/html; charset=WINDOWS-1251" +#define CHECK_CONTENT_TYPE_XML_CHRS "text/xml; charset=uTf-8" +#define CHECK_CONTENT_TYPE_TEXT "text/plain" +#define CHECK_DATE_NAME "Date" +#define CHECK_DATE_VALUE1 "Thu, 09 Jan 2014 17:58:30 GMT" +#define CHECK_DATE_VALUE2 "Thu, 09 Jan 2014 20:21:20 GMT" +#define CHECK_DATE_VALUE3 "Thu, 09 Jan 2014 20:25:02 GMT" +#define CHECK_PROT_LINE_200 "HTTP/1.1 200 OK" +#define CHECK_PROT_LINE_301 "HTTP/1.1 301 Moved Permanently" + +#define CHECK_HEADER_SMPL CHECK_PROT_LINE_200 "\r\n" \ + CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_HTML "\r\n" \ + "\r\n" + +#define CHECK_HEADER_L1 CHECK_PROT_LINE_200 "\r\n" \ + "Server: nginx/1.4.4\r\n" \ + CHECK_DATE_NAME ": " CHECK_DATE_VALUE1 "\r\n" \ + CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_HTML_CHRS "\r\n" \ + "Transfer-Encoding: chunked\r\n" \ + "Connection: close\r\n" \ + "Set-Cookie: PHPSESSID=90857d437518db8f0944ca012761048a; path=/; domain=example.com\r\n" \ + "Expires: Thu, 19 Nov 1981 08:52:00 GMT\r\n" \ + "Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0\r\n" \ + "Pragma: no-cache\r\n" \ + "Set-Cookie: user_country=ot; expires=Thu, 09-Jan-2014 18:58:30 GMT; path=/; domain=.example.com\r\n" \ + "\r\n" + +#define CHECK_HEADER_R CHECK_PROT_LINE_301 "\r\n" \ + "Server: nginx/1.4.4\r\n" \ + CHECK_DATE_NAME ": " CHECK_DATE_VALUE2 "\r\n" \ + CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_HTML "\r\n" \ + "Content-Length: 150\r\n" \ + "Connection: close\r\n" \ + "Location: http://www.Example.Com\r\n" \ + "\r\n" + +#define CHECK_HEADER_L2 CHECK_PROT_LINE_200 "\r\n" \ + CHECK_DATE_NAME ": " CHECK_DATE_VALUE3 "\r\n" \ + "Server: Apache/2.4.7 (Unix) mod_wsgi/3.4 Python/2.7.5 OpenSSL/1.0.1e\r\n" \ + "Last-Modified: Thu, 09 Jan 2014 20:10:28 GMT\r\n" \ + "ETag: \"9a97-4ef8f335ebd10\"\r\n" \ + "Accept-Ranges: bytes\r\n" \ + "Content-Length: 33355\r\n" \ + "Vary: Accept-Encoding\r\n" \ + "Cache-Control: max-age=3600\r\n" \ + "Expires: Thu, 09 Jan 2014 21:25:02 GMT\r\n" \ + "Connection: close\r\n" \ + CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_XML_CHRS "\r\n" \ + "\r\n" + +// local helper function: replace substrings +std::string strReplace(const std::string& str, const std::string& from, const std::string& to) +{ + std::string result; + size_t prevPos = 0; + size_t pos; + const size_t len = str.length(); + + do + { + pos = str.find(from, prevPos); + result.append(str, prevPos, pos - prevPos); + if (pos >= len) + break; + result.append(to); + prevPos = pos + from.length(); + } while (true); + + return result; +} + +TEST(TestHttpHeader, General) +{ + /* check freshly created object */ + CHttpHeader testHdr; + EXPECT_TRUE(testHdr.GetHeader().empty()) << "Newly created object is not empty"; + EXPECT_TRUE(testHdr.GetProtoLine().empty()) << "Newly created object has non-empty protocol line"; + EXPECT_TRUE(testHdr.GetMimeType().empty()) << "Newly created object has non-empty MIME-type"; + EXPECT_TRUE(testHdr.GetCharset().empty()) << "Newly created object has non-empty charset"; + EXPECT_TRUE(testHdr.GetValue("foo").empty()) << "Newly created object has some parameter"; + EXPECT_TRUE(testHdr.GetValues("bar").empty()) << "Newly created object has some parameters"; + EXPECT_FALSE(testHdr.IsHeaderDone()) << "Newly created object has \"parsing finished\" state"; + + /* check general functions in simple case */ + testHdr.Parse(CHECK_HEADER_SMPL); + EXPECT_FALSE(testHdr.GetHeader().empty()) << "Parsed header is empty"; + EXPECT_FALSE(testHdr.GetProtoLine().empty()) << "Parsed header has empty protocol line"; + EXPECT_FALSE(testHdr.GetMimeType().empty()) << "Parsed header has empty MIME-type"; + EXPECT_FALSE(testHdr.GetValue(CHECK_CNT_TYPE_NAME).empty()) << "Parsed header has empty \"" CHECK_CNT_TYPE_NAME "\" parameter"; + EXPECT_FALSE(testHdr.GetValues(CHECK_CNT_TYPE_NAME).empty()) << "Parsed header has no \"" CHECK_CNT_TYPE_NAME "\" parameters"; + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Parsed header has \"parsing not finished\" state"; + + /* check clearing of object */ + testHdr.Clear(); + EXPECT_TRUE(testHdr.GetHeader().empty()) << "Cleared object is not empty"; + EXPECT_TRUE(testHdr.GetProtoLine().empty()) << "Cleared object has non-empty protocol line"; + EXPECT_TRUE(testHdr.GetMimeType().empty()) << "Cleared object has non-empty MIME-type"; + EXPECT_TRUE(testHdr.GetCharset().empty()) << "Cleared object has non-empty charset"; + EXPECT_TRUE(testHdr.GetValue(CHECK_CNT_TYPE_NAME).empty()) << "Cleared object has some parameter"; + EXPECT_TRUE(testHdr.GetValues(CHECK_CNT_TYPE_NAME).empty()) << "Cleared object has some parameters"; + EXPECT_FALSE(testHdr.IsHeaderDone()) << "Cleared object has \"parsing finished\" state"; + + /* check general functions after object clearing */ + testHdr.Parse(CHECK_HEADER_R); + EXPECT_FALSE(testHdr.GetHeader().empty()) << "Parsed header is empty"; + EXPECT_FALSE(testHdr.GetProtoLine().empty()) << "Parsed header has empty protocol line"; + EXPECT_FALSE(testHdr.GetMimeType().empty()) << "Parsed header has empty MIME-type"; + EXPECT_FALSE(testHdr.GetValue(CHECK_CNT_TYPE_NAME).empty()) << "Parsed header has empty \"" CHECK_CNT_TYPE_NAME "\" parameter"; + EXPECT_FALSE(testHdr.GetValues(CHECK_CNT_TYPE_NAME).empty()) << "Parsed header has no \"" CHECK_CNT_TYPE_NAME "\" parameters"; + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Parsed header has \"parsing not finished\" state"; +} + +TEST(TestHttpHeader, Parse) +{ + CHttpHeader testHdr; + + /* check parsing line-by-line */ + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n"); + EXPECT_FALSE(testHdr.IsHeaderDone()) << "Not completed header has \"parsing finished\" state"; + testHdr.Parse(CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_HTML "\r\n"); + EXPECT_FALSE(testHdr.IsHeaderDone()) << "Not completed header has \"parsing finished\" state"; + testHdr.Parse("\r\n"); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ(CHECK_PROT_LINE_200, testHdr.GetProtoLine().c_str()) << "Wrong protocol line"; + EXPECT_STREQ(CHECK_CONTENT_TYPE_HTML, testHdr.GetValue(CHECK_CNT_TYPE_NAME).c_str()) << "Wrong value of parameter \"" CHECK_CNT_TYPE_NAME "\""; + + /* check autoclearing when new header is parsed */ + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n"); + EXPECT_FALSE(testHdr.IsHeaderDone()) << "Not completed header has \"parsing finished\" state"; + EXPECT_TRUE(testHdr.GetValues(CHECK_CNT_TYPE_NAME).empty()) << "Cleared header has some parameters"; + testHdr.Clear(); + EXPECT_TRUE(testHdr.GetHeader().empty()) << "Cleared object is not empty"; + + /* general check parsing */ + testHdr.Parse(CHECK_HEADER_SMPL); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STRCASEEQ(CHECK_HEADER_SMPL, testHdr.GetHeader().c_str()) << "Parsed header mismatch the original header"; + testHdr.Parse(CHECK_HEADER_L1); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STRCASEEQ(CHECK_HEADER_L1, testHdr.GetHeader().c_str()) << "Parsed header mismatch the original header"; + EXPECT_STREQ("Thu, 09 Jan 2014 17:58:30 GMT", testHdr.GetValue("Date").c_str()); // case-sensitive match of value + testHdr.Parse(CHECK_HEADER_L2); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STRCASEEQ(CHECK_HEADER_L2, testHdr.GetHeader().c_str()) << "Parsed header mismatch the original header"; + EXPECT_STREQ("Thu, 09 Jan 2014 20:10:28 GMT", testHdr.GetValue("Last-Modified").c_str()); // case-sensitive match of value + testHdr.Parse(CHECK_HEADER_R); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STRCASEEQ(CHECK_HEADER_R, testHdr.GetHeader().c_str()) << "Parsed header mismatch the original header"; + EXPECT_STREQ("http://www.Example.Com", testHdr.GetValue("Location").c_str()); // case-sensitive match of value + + /* check support for '\n' line endings */ + testHdr.Parse(strReplace(CHECK_HEADER_SMPL, "\r\n", "\n")); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STRCASEEQ(CHECK_HEADER_SMPL, testHdr.GetHeader().c_str()) << "Parsed header mismatch the original header"; + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + testHdr.Parse(strReplace(CHECK_HEADER_L1, "\r\n", "\n")); + EXPECT_STRCASEEQ(CHECK_HEADER_L1, testHdr.GetHeader().c_str()) << "Parsed header mismatch the original header"; + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + testHdr.Parse(strReplace(CHECK_HEADER_L2, "\r\n", "\n")); + EXPECT_STRCASEEQ(CHECK_HEADER_L2, testHdr.GetHeader().c_str()) << "Parsed header mismatch the original header"; + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + testHdr.Parse(CHECK_PROT_LINE_200 "\n" CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_HTML "\r\n"); // mixed "\n" and "\r\n" + testHdr.Parse("\n"); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STRCASEEQ(CHECK_PROT_LINE_200 "\r\n" CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_HTML "\r\n\r\n", testHdr.GetHeader().c_str()) << "Parsed header mismatch the original header"; + EXPECT_STREQ(CHECK_CONTENT_TYPE_HTML, testHdr.GetValue(CHECK_CNT_TYPE_NAME).c_str()) << "Wrong value of parameter \"" CHECK_CNT_TYPE_NAME "\""; + + /* check trimming of whitespaces for parameter name and value */ + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n" CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_HTML "\r\n\r\n"); + EXPECT_STREQ(CHECK_CONTENT_TYPE_HTML, testHdr.GetValue(CHECK_CNT_TYPE_NAME).c_str()) << "Wrong value of parameter \"" CHECK_CNT_TYPE_NAME "\""; + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n" CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_HTML " \r\n\r\n"); + EXPECT_STREQ(CHECK_CONTENT_TYPE_HTML, testHdr.GetValue(CHECK_CNT_TYPE_NAME).c_str()) << "Wrong value of parameter \"" CHECK_CNT_TYPE_NAME "\""; + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n" CHECK_CNT_TYPE_NAME ":" CHECK_CONTENT_TYPE_HTML " \r\n\r\n"); + EXPECT_STREQ(CHECK_CONTENT_TYPE_HTML, testHdr.GetValue(CHECK_CNT_TYPE_NAME).c_str()) << "Wrong value of parameter \"" CHECK_CNT_TYPE_NAME "\""; + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n" CHECK_CNT_TYPE_NAME ":\t" CHECK_CONTENT_TYPE_HTML " \t \r\n\r\n"); + EXPECT_STREQ(CHECK_CONTENT_TYPE_HTML, testHdr.GetValue(CHECK_CNT_TYPE_NAME).c_str()) << "Wrong value of parameter \"" CHECK_CNT_TYPE_NAME "\""; + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n" CHECK_CNT_TYPE_NAME ":\t " CHECK_CONTENT_TYPE_HTML " \t \r\n\r\n"); + EXPECT_STREQ(CHECK_CONTENT_TYPE_HTML, testHdr.GetValue(CHECK_CNT_TYPE_NAME).c_str()) << "Wrong value of parameter \"" CHECK_CNT_TYPE_NAME "\""; + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n" CHECK_CNT_TYPE_NAME "\t:" CHECK_CONTENT_TYPE_HTML " \t \r\n\r\n"); + EXPECT_STREQ(CHECK_CONTENT_TYPE_HTML, testHdr.GetValue(CHECK_CNT_TYPE_NAME).c_str()) << "Wrong value of parameter \"" CHECK_CNT_TYPE_NAME "\""; + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n" CHECK_CNT_TYPE_NAME " \t : " CHECK_CONTENT_TYPE_HTML " \t \r\n\r\n"); + EXPECT_STREQ(CHECK_CONTENT_TYPE_HTML, testHdr.GetValue(CHECK_CNT_TYPE_NAME).c_str()) << "Wrong value of parameter \"" CHECK_CNT_TYPE_NAME "\""; +} + +TEST(TestHttpHeader, Parse_Multiline) +{ + CHttpHeader testHdr; + + /* Check multiline parameter parsing line-by-line */ + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n"); + testHdr.Parse(CHECK_DATE_NAME ": " CHECK_DATE_VALUE3 "\r\n"); + testHdr.Parse("X-Comment: This\r\n"); // between singleline parameters + testHdr.Parse(" is\r\n"); + testHdr.Parse(" multi\r\n"); + testHdr.Parse(" line\r\n"); + testHdr.Parse(" value\r\n"); + testHdr.Parse(CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_TEXT "\r\n"); + testHdr.Parse("\r\n"); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is multi line value", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n"); + testHdr.Parse("X-Comment: This\r\n"); // first parameter + testHdr.Parse(" is\r\n"); + testHdr.Parse(" multi\r\n"); + testHdr.Parse(" line\r\n"); + testHdr.Parse(" value\r\n"); + testHdr.Parse(CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_TEXT "\r\n"); + testHdr.Parse("\r\n"); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is multi line value", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n"); + testHdr.Parse(CHECK_DATE_NAME ": " CHECK_DATE_VALUE3 "\r\n"); + testHdr.Parse("X-Comment: This\r\n"); // last parameter + testHdr.Parse(" is\r\n"); + testHdr.Parse(" multi\r\n"); + testHdr.Parse(" line\r\n"); + testHdr.Parse(" value\r\n"); + testHdr.Parse("\r\n"); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is multi line value", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n"); + testHdr.Parse("X-Comment: This\r\n"); // the only parameter + testHdr.Parse(" is\r\n"); + testHdr.Parse(" multi\r\n"); + testHdr.Parse(" line\r\n"); + testHdr.Parse(" value\r\n"); + testHdr.Parse("\r\n"); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is multi line value", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n"); + testHdr.Parse("X-Comment: This\n"); // the only parameter with mixed ending style + testHdr.Parse(" is\r\n"); + testHdr.Parse(" multi\n"); + testHdr.Parse(" line\r\n"); + testHdr.Parse(" value\n"); + testHdr.Parse("\r\n"); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is multi line value", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + /* Check multiline parameter parsing as one line */ + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n" CHECK_DATE_NAME ": " CHECK_DATE_VALUE3 "\r\nX-Comment: This\r\n is\r\n multi\r\n line\r\n value\r\n" \ + CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_TEXT "\r\n\r\n"); // between singleline parameters + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is multi line value", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\nX-Comment: This\r\n is\r\n multi\r\n line\r\n value\r\n" \ + CHECK_CNT_TYPE_NAME ": " CHECK_CONTENT_TYPE_TEXT "\r\n\r\n"); // first parameter + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is multi line value", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n" CHECK_DATE_NAME ": " CHECK_DATE_VALUE3 "\r\nX-Comment: This\r\n is\r\n multi\r\n line\r\n value\r\n\r\n"); // last parameter + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is multi line value", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\nX-Comment: This\r\n is\r\n multi\r\n line\r\n value\r\n\r\n"); // the only parameter + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is multi line value", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\nX-Comment: This\n is\r\n multi\r\n line\n value\r\n\n"); // the only parameter with mixed ending style + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is multi line value", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + /* Check multiline parameter parsing as mixed one/many lines */ + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\nX-Comment: This\n is\r\n multi\r\n"); + testHdr.Parse(" line\n value\r\n\n"); // the only parameter with mixed ending style + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is multi line value", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + /* Check parsing of multiline parameter with ':' in value */ + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\nX-Comment: This\r\n is:\r\n mul:ti\r\n"); + testHdr.Parse(" :line\r\n valu:e\r\n\n"); // the only parameter + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("This is: mul:ti :line valu:e", testHdr.GetValue("X-Comment").c_str()) << "Wrong multiline value"; + + /* Check multiline parameter parsing with trimming */ + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n"); + testHdr.Parse(CHECK_DATE_NAME ": " CHECK_DATE_VALUE3 "\r\n"); + testHdr.Parse("Server: Apache/2.4.7 (Unix)\r\n"); // last parameter, line-by-line parsing + testHdr.Parse(" mod_wsgi/3.4 \r\n"); + testHdr.Parse("\tPython/2.7.5\r\n"); + testHdr.Parse("\t \t \tOpenSSL/1.0.1e\r\n"); + testHdr.Parse("\r\n"); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_GE(strlen("Apache/2.4.7 (Unix) mod_wsgi/3.4 \tPython/2.7.5\t \t \tOpenSSL/1.0.1e"), testHdr.GetValue("Server").length()) << "Length of miltiline value is greater than length of original string"; + EXPECT_LE(strlen("Apache/2.4.7 (Unix) mod_wsgi/3.4 Python/2.7.5 OpenSSL/1.0.1e"), testHdr.GetValue("Server").length()) << "Length of miltiline value is less than length of trimmed original string"; + EXPECT_STREQ("Apache/2.4.7(Unix)mod_wsgi/3.4Python/2.7.5OpenSSL/1.0.1e", strReplace(strReplace(testHdr.GetValue("Server"), " ", ""), "\t", "").c_str()) << "Multiline value with removed whitespaces does not match original string with removed whitespaces"; + + testHdr.Clear(); + testHdr.Parse(CHECK_PROT_LINE_200 "\r\n"); + testHdr.Parse(CHECK_DATE_NAME ": " CHECK_DATE_VALUE3 "\r\n"); + testHdr.Parse("Server: Apache/2.4.7 (Unix)\r\n mod_wsgi/3.4 \n"); // last parameter, mixed line-by-line/one line parsing, mixed line ending + testHdr.Parse("\tPython/2.7.5\n\t \t \tOpenSSL/1.0.1e\r\n"); + testHdr.Parse("\r\n"); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_GE(strlen("Apache/2.4.7 (Unix) mod_wsgi/3.4 \tPython/2.7.5\t \t \tOpenSSL/1.0.1e"), testHdr.GetValue("Server").length()) << "Length of miltiline value is greater than length of original string"; + EXPECT_LE(strlen("Apache/2.4.7 (Unix) mod_wsgi/3.4 Python/2.7.5 OpenSSL/1.0.1e"), testHdr.GetValue("Server").length()) << "Length of miltiline value is less than length of trimmed original string"; + EXPECT_STREQ("Apache/2.4.7(Unix)mod_wsgi/3.4Python/2.7.5OpenSSL/1.0.1e", strReplace(strReplace(testHdr.GetValue("Server"), " ", ""), "\t", "").c_str()) << "Multiline value with removed whitespaces does not match original string with removed whitespaces"; +} + +TEST(TestHttpHeader, GetValue) +{ + CHttpHeader testHdr; + + /* Check that all parameters values can be retrieved */ + testHdr.Parse(CHECK_HEADER_R); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("nginx/1.4.4", testHdr.GetValue("Server").c_str()) << "Wrong parameter value"; + EXPECT_STREQ(CHECK_DATE_VALUE2, testHdr.GetValue(CHECK_DATE_NAME).c_str()) << "Wrong parameter value"; + EXPECT_STREQ(CHECK_CONTENT_TYPE_HTML, testHdr.GetValue(CHECK_CNT_TYPE_NAME).c_str()) << "Wrong parameter value"; + EXPECT_STREQ("150", testHdr.GetValue("Content-Length").c_str()) << "Wrong parameter value"; + EXPECT_STREQ("close", testHdr.GetValue("Connection").c_str()) << "Wrong parameter value"; + EXPECT_STREQ("http://www.Example.Com", testHdr.GetValue("Location").c_str()) << "Wrong parameter value"; + EXPECT_TRUE(testHdr.GetValue("foo").empty()) << "Some value is returned for non-existed parameter"; + + /* Check that all parameters values can be retrieved in random order */ + testHdr.Parse(CHECK_HEADER_R); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Completed header has \"parsing not finished\" state"; + EXPECT_STREQ("http://www.Example.Com", testHdr.GetValue("Location").c_str()) << "Wrong parameter value"; + EXPECT_STREQ(CHECK_CONTENT_TYPE_HTML, testHdr.GetValue(CHECK_CNT_TYPE_NAME).c_str()) << "Wrong parameter value"; + EXPECT_STREQ("http://www.Example.Com", testHdr.GetValue("Location").c_str()) << "Wrong parameter value"; + EXPECT_STREQ("close", testHdr.GetValue("Connection").c_str()) << "Wrong parameter value"; + EXPECT_STREQ("nginx/1.4.4", testHdr.GetValue("Server").c_str()) << "Wrong parameter value"; + EXPECT_STREQ("150", testHdr.GetValue("Content-Length").c_str()) << "Wrong parameter value"; + EXPECT_STREQ(CHECK_DATE_VALUE2, testHdr.GetValue(CHECK_DATE_NAME).c_str()) << "Wrong parameter value"; + EXPECT_STREQ("nginx/1.4.4", testHdr.GetValue("Server").c_str()) << "Wrong parameter value"; + EXPECT_TRUE(testHdr.GetValue("foo").empty()) << "Some value is returned for non-existed parameter"; + + /* Check that parameters name is case-insensitive and value is case-sensitive*/ + EXPECT_STREQ("http://www.Example.Com", testHdr.GetValue("location").c_str()) << "Wrong parameter value for lowercase name"; + EXPECT_STREQ("http://www.Example.Com", testHdr.GetValue("LOCATION").c_str()) << "Wrong parameter value for UPPERCASE name"; + EXPECT_STREQ("http://www.Example.Com", testHdr.GetValue("LoCAtIOn").c_str()) << "Wrong parameter value for MiXEdcASe name"; + + /* Check value of last added parameter with the same name is returned */ + testHdr.Parse(CHECK_HEADER_L1); + EXPECT_STREQ("close", testHdr.GetValue("Connection").c_str()) << "Wrong parameter value"; + EXPECT_STREQ("user_country=ot; expires=Thu, 09-Jan-2014 18:58:30 GMT; path=/; domain=.example.com", testHdr.GetValue("Set-Cookie").c_str()) << "Wrong parameter value"; + EXPECT_STREQ("user_country=ot; expires=Thu, 09-Jan-2014 18:58:30 GMT; path=/; domain=.example.com", testHdr.GetValue("set-cookie").c_str()) << "Wrong parameter value for lowercase name"; +} + +TEST(TestHttpHeader, GetValues) +{ + CHttpHeader testHdr; + + /* Check that all parameter values can be retrieved and order of values is correct */ + testHdr.Parse(CHECK_HEADER_L1); + EXPECT_EQ(1U, testHdr.GetValues("Server").size()) << "Wrong number of values for parameter \"Server\""; + EXPECT_STREQ("nginx/1.4.4", testHdr.GetValues("Server")[0].c_str()) << "Wrong parameter value"; + EXPECT_EQ(2U, testHdr.GetValues("Set-Cookie").size()) << "Wrong number of values for parameter \"Set-Cookie\""; + EXPECT_STREQ("PHPSESSID=90857d437518db8f0944ca012761048a; path=/; domain=example.com", testHdr.GetValues("Set-Cookie")[0].c_str()) << "Wrong parameter value"; + EXPECT_STREQ("user_country=ot; expires=Thu, 09-Jan-2014 18:58:30 GMT; path=/; domain=.example.com", testHdr.GetValues("Set-Cookie")[1].c_str()) << "Wrong parameter value"; + EXPECT_TRUE(testHdr.GetValues("foo").empty()) << "Some values are returned for non-existed parameter"; +} + +TEST(TestHttpHeader, AddParam) +{ + CHttpHeader testHdr; + + /* General functionality */ + testHdr.AddParam("server", "Microsoft-IIS/8.0"); + EXPECT_STREQ("Microsoft-IIS/8.0", testHdr.GetValue("Server").c_str()) << "Wrong parameter value"; + + /* Interfere with parsing */ + EXPECT_FALSE(testHdr.IsHeaderDone()) << "\"AddParam\" set \"parsing finished\" state"; + testHdr.Parse(CHECK_PROT_LINE_200 "\r\nServer: nginx/1.4.4\r\n\r\n"); + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Parsed header has \"parsing not finished\" state"; + EXPECT_STREQ("nginx/1.4.4", testHdr.GetValue("Server").c_str()) << "Wrong parameter value"; + testHdr.AddParam("server", "Apache/2.4.7"); + EXPECT_STREQ("Apache/2.4.7", testHdr.GetValue("Server").c_str()) << "Wrong parameter value"; + EXPECT_EQ(3U, testHdr.GetValues("Server").size()) << "Wrong number of values for parameter \"Server\""; + + /* Multiple values */ + testHdr.AddParam("X-foo", "bar1"); + testHdr.AddParam("x-foo", "bar2"); + testHdr.AddParam("x-fOO", "bar3"); + EXPECT_EQ(3U, testHdr.GetValues("X-FOO").size()) << "Wrong number of values for parameter \"X-foo\""; + EXPECT_STREQ("bar1", testHdr.GetValues("X-FOo")[0].c_str()) << "Wrong parameter value"; + EXPECT_STREQ("bar2", testHdr.GetValues("X-fOo")[1].c_str()) << "Wrong parameter value"; + EXPECT_STREQ("bar3", testHdr.GetValues("x-fOo")[2].c_str()) << "Wrong parameter value"; + EXPECT_STREQ("bar3", testHdr.GetValue("x-foo").c_str()) << "Wrong parameter value"; + + /* Overwrite value */ + EXPECT_TRUE(testHdr.IsHeaderDone()) << "Parsed header has \"parsing not finished\" state"; + testHdr.AddParam("x-fOO", "superbar", true); + EXPECT_EQ(1U, testHdr.GetValues("X-FoO").size()) << "Wrong number of values for parameter \"X-foo\""; + EXPECT_STREQ("superbar", testHdr.GetValue("x-foo").c_str()) << "Wrong parameter value"; + + /* Check name trimming */ + testHdr.AddParam("\tx-fOO\t ", "bar"); + EXPECT_EQ(2U, testHdr.GetValues("X-FoO").size()) << "Wrong number of values for parameter \"X-foo\""; + EXPECT_STREQ("bar", testHdr.GetValue("x-foo").c_str()) << "Wrong parameter value"; + testHdr.AddParam(" SerVer \t ", "fakeSrv", true); + EXPECT_EQ(1U, testHdr.GetValues("serveR").size()) << "Wrong number of values for parameter \"Server\""; + EXPECT_STREQ("fakeSrv", testHdr.GetValue("Server").c_str()) << "Wrong parameter value"; + + /* Check value trimming */ + testHdr.AddParam("X-TestParam", " testValue1"); + EXPECT_STREQ("testValue1", testHdr.GetValue("X-TestParam").c_str()) << "Wrong parameter value"; + testHdr.AddParam("X-TestParam", "\ttestValue2 and more \t "); + EXPECT_STREQ("testValue2 and more", testHdr.GetValue("X-TestParam").c_str()) << "Wrong parameter value"; + + /* Empty name or value */ + testHdr.Clear(); + testHdr.AddParam("X-TestParam", " "); + EXPECT_TRUE(testHdr.GetHeader().empty()) << "Parameter with empty value was added"; + testHdr.AddParam("\t\t", "value"); + EXPECT_TRUE(testHdr.GetHeader().empty()); + testHdr.AddParam(" ", "\t"); + EXPECT_TRUE(testHdr.GetHeader().empty()); +} + +TEST(TestHttpHeader, GetMimeType) +{ + CHttpHeader testHdr; + + /* General functionality */ + EXPECT_TRUE(testHdr.GetMimeType().empty()) << "Newly created object has non-empty MIME-type"; + testHdr.Parse(CHECK_PROT_LINE_200 "\r\nServer: nginx/1.4.4\r\n\r\n"); + EXPECT_TRUE(testHdr.GetMimeType().empty()) << "Non-empty MIME-type for header without MIME-type"; + testHdr.Parse(CHECK_HEADER_SMPL); + EXPECT_STREQ("text/html", testHdr.GetMimeType().c_str()) << "Wrong MIME-type"; + testHdr.Parse(CHECK_HEADER_L1); + EXPECT_STREQ("text/html", testHdr.GetMimeType().c_str()) << "Wrong MIME-type"; + testHdr.Parse(CHECK_HEADER_L2); + EXPECT_STREQ("text/xml", testHdr.GetMimeType().c_str()) << "Wrong MIME-type"; + testHdr.Parse(CHECK_HEADER_R); + EXPECT_STREQ("text/html", testHdr.GetMimeType().c_str()) << "Wrong MIME-type"; + + /* Overwrite by AddParam */ + testHdr.AddParam(CHECK_CNT_TYPE_NAME, CHECK_CONTENT_TYPE_TEXT); + EXPECT_STREQ(CHECK_CONTENT_TYPE_TEXT, testHdr.GetMimeType().c_str()) << "MIME-type was not overwritten by \"AddParam\""; + + /* Correct trimming */ + testHdr.AddParam(CHECK_CNT_TYPE_NAME, " " CHECK_CONTENT_TYPE_TEXT " \t ;foo=bar"); + EXPECT_STREQ(CHECK_CONTENT_TYPE_TEXT, testHdr.GetMimeType().c_str()) << "MIME-type is not trimmed correctly"; +} + + +TEST(TestHttpHeader, GetCharset) +{ + CHttpHeader testHdr; + + /* General functionality */ + EXPECT_TRUE(testHdr.GetCharset().empty()) << "Newly created object has non-empty charset"; + testHdr.Parse(CHECK_PROT_LINE_200 "\r\nServer: nginx/1.4.4\r\n\r\n"); + EXPECT_TRUE(testHdr.GetCharset().empty()) << "Non-empty charset for header without charset"; + testHdr.Parse(CHECK_HEADER_SMPL); + EXPECT_TRUE(testHdr.GetCharset().empty()) << "Non-empty charset for header without charset"; + testHdr.Parse(CHECK_HEADER_L1); + EXPECT_STREQ("WINDOWS-1251", testHdr.GetCharset().c_str()) << "Wrong charset value"; + testHdr.Parse(CHECK_HEADER_L2); + EXPECT_STREQ("UTF-8", testHdr.GetCharset().c_str()) << "Wrong charset value"; + + /* Overwrite by AddParam */ + testHdr.AddParam(CHECK_CNT_TYPE_NAME, CHECK_CONTENT_TYPE_TEXT "; charset=WINDOWS-1252"); + EXPECT_STREQ("WINDOWS-1252", testHdr.GetCharset().c_str()) << "Charset was not overwritten by \"AddParam\""; + + /* Correct trimming */ + testHdr.AddParam(CHECK_CNT_TYPE_NAME, "text/plain;charset=WINDOWS-1251"); + EXPECT_STREQ("WINDOWS-1251", testHdr.GetCharset().c_str()) << "Wrong charset value"; + testHdr.AddParam(CHECK_CNT_TYPE_NAME, "text/plain ;\tcharset=US-AScII\t"); + EXPECT_STREQ("US-ASCII", testHdr.GetCharset().c_str()) << "Wrong charset value"; + testHdr.AddParam(CHECK_CNT_TYPE_NAME, "text/html ; \tcharset=\"uTF-8\"\t"); + EXPECT_STREQ("UTF-8", testHdr.GetCharset().c_str()) << "Wrong charset value"; + testHdr.AddParam(CHECK_CNT_TYPE_NAME, " \ttext/xml\t;\tcharset=uTF-16 "); + EXPECT_STREQ("UTF-16", testHdr.GetCharset().c_str()) << "Wrong charset value"; +} diff --git a/xbmc/utils/test/TestHttpParser.cpp b/xbmc/utils/test/TestHttpParser.cpp new file mode 100644 index 0000000..1eb2932 --- /dev/null +++ b/xbmc/utils/test/TestHttpParser.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/HttpParser.h" + +#include <gtest/gtest.h> + +TEST(TestHttpParser, General) +{ + HttpParser a; + std::string str = "POST /path/script.cgi HTTP/1.0\r\n" + "From: amejia@xbmc.org\r\n" + "User-Agent: XBMC/snapshot (compatible; MSIE 5.5; Windows NT" + " 4.0)\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "Content-Length: 35\r\n" + "\r\n" + "home=amejia&favorite+flavor=orange\r\n"; + std::string refstr, varstr; + + EXPECT_EQ(a.Done, a.addBytes(str.c_str(), str.length())); + + refstr = "POST"; + varstr = a.getMethod(); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "/path/script.cgi"; + varstr = a.getUri(); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = ""; + varstr = a.getQueryString(); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "home=amejia&favorite+flavor=orange\r\n"; + varstr = a.getBody(); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "application/x-www-form-urlencoded"; + varstr = a.getValue("content-type"); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + EXPECT_EQ((unsigned)35, a.getContentLength()); +} diff --git a/xbmc/utils/test/TestHttpRangeUtils.cpp b/xbmc/utils/test/TestHttpRangeUtils.cpp new file mode 100644 index 0000000..f988f10 --- /dev/null +++ b/xbmc/utils/test/TestHttpRangeUtils.cpp @@ -0,0 +1,887 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/HttpRangeUtils.h" + +#include <gtest/gtest.h> + +#define RANGES_START "bytes=" + +static const uint64_t DefaultFirstPosition = 1; +static const uint64_t DefaultLastPosition = 0; +static const uint64_t DefaultLength = 0; +static const void* DefaultData = NULL; + +TEST(TestHttpRange, FirstPosition) +{ + const uint64_t expectedFirstPosition = 25; + + CHttpRange range; + EXPECT_EQ(DefaultFirstPosition, range.GetFirstPosition()); + + range.SetFirstPosition(expectedFirstPosition); + EXPECT_EQ(expectedFirstPosition, range.GetFirstPosition()); +} + +TEST(TestHttpRange, LastPosition) +{ + const uint64_t expectedLastPosition = 25; + + CHttpRange range; + EXPECT_EQ(DefaultLastPosition, range.GetLastPosition()); + + range.SetLastPosition(expectedLastPosition); + EXPECT_EQ(expectedLastPosition, range.GetLastPosition()); +} + +TEST(TestHttpRange, Length) +{ + const uint64_t expectedFirstPosition = 10; + const uint64_t expectedLastPosition = 25; + const uint64_t expectedLength = expectedLastPosition - expectedFirstPosition + 1; + + CHttpRange range; + EXPECT_EQ(DefaultLength, range.GetLength()); + + range.SetFirstPosition(expectedFirstPosition); + range.SetLastPosition(expectedLastPosition); + EXPECT_EQ(expectedLength, range.GetLength()); + + CHttpRange range_length; + range.SetFirstPosition(expectedFirstPosition); + range.SetLength(expectedLength); + EXPECT_EQ(expectedLastPosition, range.GetLastPosition()); + EXPECT_EQ(expectedLength, range.GetLength()); +} + +TEST(TestHttpRange, IsValid) +{ + const uint64_t validFirstPosition = 10; + const uint64_t validLastPosition = 25; + const uint64_t invalidLastPosition = 5; + + CHttpRange range; + EXPECT_FALSE(range.IsValid()); + + range.SetFirstPosition(validFirstPosition); + EXPECT_FALSE(range.IsValid()); + + range.SetLastPosition(invalidLastPosition); + EXPECT_FALSE(range.IsValid()); + + range.SetLastPosition(validLastPosition); + EXPECT_TRUE(range.IsValid()); +} + +TEST(TestHttpRange, Ctor) +{ + const uint64_t validFirstPosition = 10; + const uint64_t validLastPosition = 25; + const uint64_t invalidLastPosition = 5; + const uint64_t validLength = validLastPosition - validFirstPosition + 1; + + CHttpRange range_invalid(validFirstPosition, invalidLastPosition); + EXPECT_EQ(validFirstPosition, range_invalid.GetFirstPosition()); + EXPECT_EQ(invalidLastPosition, range_invalid.GetLastPosition()); + EXPECT_EQ(DefaultLength, range_invalid.GetLength()); + EXPECT_FALSE(range_invalid.IsValid()); + + CHttpRange range_valid(validFirstPosition, validLastPosition); + EXPECT_EQ(validFirstPosition, range_valid.GetFirstPosition()); + EXPECT_EQ(validLastPosition, range_valid.GetLastPosition()); + EXPECT_EQ(validLength, range_valid.GetLength()); + EXPECT_TRUE(range_valid.IsValid()); +} + +TEST(TestHttpResponseRange, SetData) +{ + const uint64_t validFirstPosition = 1; + const uint64_t validLastPosition = 2; + const uint64_t validLength = validLastPosition - validFirstPosition + 1; + const char* validData = "test"; + const void* invalidData = DefaultData; + const size_t validDataLength = strlen(validData); + const size_t invalidDataLength = 1; + + CHttpResponseRange range; + EXPECT_EQ(DefaultData, range.GetData()); + EXPECT_FALSE(range.IsValid()); + + range.SetData(invalidData); + EXPECT_EQ(invalidData, range.GetData()); + EXPECT_FALSE(range.IsValid()); + + range.SetData(validData); + EXPECT_EQ(validData, range.GetData()); + EXPECT_FALSE(range.IsValid()); + + range.SetData(invalidData, 0); + EXPECT_EQ(validData, range.GetData()); + EXPECT_FALSE(range.IsValid()); + + range.SetData(invalidData, invalidDataLength); + EXPECT_EQ(invalidData, range.GetData()); + EXPECT_FALSE(range.IsValid()); + + range.SetData(validData, validDataLength); + EXPECT_EQ(validData, range.GetData()); + EXPECT_EQ(0U, range.GetFirstPosition()); + EXPECT_EQ(validDataLength - 1, range.GetLastPosition()); + EXPECT_EQ(validDataLength, range.GetLength()); + EXPECT_TRUE(range.IsValid()); + + range.SetData(invalidData, 0, 0); + EXPECT_EQ(invalidData, range.GetData()); + EXPECT_FALSE(range.IsValid()); + + range.SetData(validData, validFirstPosition, validLastPosition); + EXPECT_EQ(validData, range.GetData()); + EXPECT_EQ(validFirstPosition, range.GetFirstPosition()); + EXPECT_EQ(validLastPosition, range.GetLastPosition()); + EXPECT_EQ(validLength, range.GetLength()); + EXPECT_TRUE(range.IsValid()); +} + +TEST(TestHttpRanges, Ctor) +{ + CHttpRange range; + uint64_t position; + + CHttpRanges ranges_empty; + + EXPECT_EQ(0U, ranges_empty.Size()); + EXPECT_TRUE(ranges_empty.Get().empty()); + + EXPECT_FALSE(ranges_empty.Get(0, range)); + EXPECT_FALSE(ranges_empty.GetFirst(range)); + EXPECT_FALSE(ranges_empty.GetLast(range)); + + EXPECT_FALSE(ranges_empty.GetFirstPosition(position)); + EXPECT_FALSE(ranges_empty.GetLastPosition(position)); + EXPECT_EQ(0U, ranges_empty.GetLength()); + EXPECT_FALSE(ranges_empty.GetTotalRange(range)); +} + +TEST(TestHttpRanges, GetAll) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + + HttpRanges ranges_raw; + ranges_raw.push_back(range_0); + ranges_raw.push_back(range_1); + ranges_raw.push_back(range_2); + + CHttpRanges ranges(ranges_raw); + + const HttpRanges& ranges_raw_get = ranges.Get(); + ASSERT_EQ(ranges_raw.size(), ranges_raw_get.size()); + + for (size_t i = 0; i < ranges_raw.size(); ++i) + EXPECT_EQ(ranges_raw.at(i), ranges_raw_get.at(i)); +} + +TEST(TestHttpRanges, GetIndex) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + + HttpRanges ranges_raw; + ranges_raw.push_back(range_0); + ranges_raw.push_back(range_1); + ranges_raw.push_back(range_2); + + CHttpRanges ranges(ranges_raw); + + CHttpRange range; + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range_0, range); + + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range_1, range); + + EXPECT_TRUE(ranges.Get(2, range)); + EXPECT_EQ(range_2, range); + + EXPECT_FALSE(ranges.Get(3, range)); +} + +TEST(TestHttpRanges, GetFirst) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + + HttpRanges ranges_raw; + ranges_raw.push_back(range_0); + ranges_raw.push_back(range_1); + ranges_raw.push_back(range_2); + + CHttpRanges ranges(ranges_raw); + + CHttpRange range; + EXPECT_TRUE(ranges.GetFirst(range)); + EXPECT_EQ(range_0, range); +} + +TEST(TestHttpRanges, GetLast) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + + HttpRanges ranges_raw; + ranges_raw.push_back(range_0); + ranges_raw.push_back(range_1); + ranges_raw.push_back(range_2); + + CHttpRanges ranges(ranges_raw); + + CHttpRange range; + EXPECT_TRUE(ranges.GetLast(range)); + EXPECT_EQ(range_2, range); +} + +TEST(TestHttpRanges, Size) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + + HttpRanges ranges_raw; + ranges_raw.push_back(range_0); + ranges_raw.push_back(range_1); + ranges_raw.push_back(range_2); + + CHttpRanges ranges_empty; + EXPECT_EQ(0U, ranges_empty.Size()); + + CHttpRanges ranges(ranges_raw); + EXPECT_EQ(ranges_raw.size(), ranges.Size()); +} + +TEST(TestHttpRanges, GetFirstPosition) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + + HttpRanges ranges_raw; + ranges_raw.push_back(range_0); + ranges_raw.push_back(range_1); + ranges_raw.push_back(range_2); + + CHttpRanges ranges(ranges_raw); + + uint64_t position; + EXPECT_TRUE(ranges.GetFirstPosition(position)); + EXPECT_EQ(range_0.GetFirstPosition(), position); +} + +TEST(TestHttpRanges, GetLastPosition) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + + HttpRanges ranges_raw; + ranges_raw.push_back(range_0); + ranges_raw.push_back(range_1); + ranges_raw.push_back(range_2); + + CHttpRanges ranges(ranges_raw); + + uint64_t position; + EXPECT_TRUE(ranges.GetLastPosition(position)); + EXPECT_EQ(range_2.GetLastPosition(), position); +} + +TEST(TestHttpRanges, GetLength) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + const uint64_t expectedLength = range_0.GetLength() + range_1.GetLength() + range_2.GetLength(); + + HttpRanges ranges_raw; + ranges_raw.push_back(range_0); + ranges_raw.push_back(range_1); + ranges_raw.push_back(range_2); + + CHttpRanges ranges(ranges_raw); + + EXPECT_EQ(expectedLength, ranges.GetLength()); +} + +TEST(TestHttpRanges, GetTotalRange) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + CHttpRange range_total_expected(range_0.GetFirstPosition(), range_2.GetLastPosition()); + + HttpRanges ranges_raw; + ranges_raw.push_back(range_0); + ranges_raw.push_back(range_1); + ranges_raw.push_back(range_2); + + CHttpRanges ranges(ranges_raw); + + CHttpRange range_total; + EXPECT_TRUE(ranges.GetTotalRange(range_total)); + EXPECT_EQ(range_total_expected, range_total); +} + +TEST(TestHttpRanges, Add) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + + CHttpRanges ranges; + CHttpRange range; + + ranges.Add(range_0); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.GetFirst(range)); + EXPECT_EQ(range_0, range); + EXPECT_TRUE(ranges.GetLast(range)); + EXPECT_EQ(range_0, range); + + ranges.Add(range_1); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.GetFirst(range)); + EXPECT_EQ(range_0, range); + EXPECT_TRUE(ranges.GetLast(range)); + EXPECT_EQ(range_1, range); + + ranges.Add(range_2); + EXPECT_EQ(3U, ranges.Size()); + EXPECT_TRUE(ranges.GetFirst(range)); + EXPECT_EQ(range_0, range); + EXPECT_TRUE(ranges.GetLast(range)); + EXPECT_EQ(range_2, range); +} + +TEST(TestHttpRanges, Remove) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + + HttpRanges ranges_raw; + ranges_raw.push_back(range_0); + ranges_raw.push_back(range_1); + ranges_raw.push_back(range_2); + + CHttpRanges ranges(ranges_raw); + + CHttpRange range; + EXPECT_EQ(3U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range_1, range); + EXPECT_TRUE(ranges.Get(2, range)); + EXPECT_EQ(range_2, range); + + // remove non-existing range + ranges.Remove(ranges.Size()); + EXPECT_EQ(3U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range_1, range); + EXPECT_TRUE(ranges.Get(2, range)); + EXPECT_EQ(range_2, range); + + // remove first range + ranges.Remove(0); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range_1, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range_2, range); + + // remove last range + ranges.Remove(1); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range_1, range); + + // remove remaining range + ranges.Remove(0); + EXPECT_EQ(0U, ranges.Size()); +} + +TEST(TestHttpRanges, Clear) +{ + CHttpRange range_0(0, 2); + CHttpRange range_1(4, 6); + CHttpRange range_2(8, 10); + + HttpRanges ranges_raw; + ranges_raw.push_back(range_0); + ranges_raw.push_back(range_1); + ranges_raw.push_back(range_2); + + CHttpRanges ranges(ranges_raw); + + CHttpRange range; + EXPECT_EQ(3U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range_1, range); + EXPECT_TRUE(ranges.Get(2, range)); + EXPECT_EQ(range_2, range); + + ranges.Clear(); + EXPECT_EQ(0U, ranges.Size()); +} + +TEST(TestHttpRanges, ParseInvalid) +{ + CHttpRanges ranges; + + // combinations of invalid string and invalid total length + EXPECT_FALSE(ranges.Parse("")); + EXPECT_FALSE(ranges.Parse("", 0)); + EXPECT_FALSE(ranges.Parse("", 1)); + EXPECT_FALSE(ranges.Parse("test", 0)); + EXPECT_FALSE(ranges.Parse(RANGES_START, 0)); + + // empty range definition + EXPECT_FALSE(ranges.Parse(RANGES_START)); + EXPECT_FALSE(ranges.Parse(RANGES_START "-")); + + // bad characters in range definition + EXPECT_FALSE(ranges.Parse(RANGES_START "a")); + EXPECT_FALSE(ranges.Parse(RANGES_START "1a")); + EXPECT_FALSE(ranges.Parse(RANGES_START "1-a")); + EXPECT_FALSE(ranges.Parse(RANGES_START "a-a")); + EXPECT_FALSE(ranges.Parse(RANGES_START "a-1")); + EXPECT_FALSE(ranges.Parse(RANGES_START "--")); + EXPECT_FALSE(ranges.Parse(RANGES_START "1--")); + EXPECT_FALSE(ranges.Parse(RANGES_START "1--2")); + EXPECT_FALSE(ranges.Parse(RANGES_START "--2")); + + // combination of valid and empty range definitions + EXPECT_FALSE(ranges.Parse(RANGES_START "0-1,")); + EXPECT_FALSE(ranges.Parse(RANGES_START ",0-1")); + + // too big start position + EXPECT_FALSE(ranges.Parse(RANGES_START "10-11", 5)); + + // end position smaller than start position + EXPECT_FALSE(ranges.Parse(RANGES_START "1-0")); +} + +TEST(TestHttpRanges, ParseStartOnly) +{ + const uint64_t totalLength = 5; + const CHttpRange range0_(0, totalLength - 1); + const CHttpRange range2_(2, totalLength - 1); + + CHttpRange range; + + CHttpRanges ranges_all; + EXPECT_TRUE(ranges_all.Parse(RANGES_START "0-", totalLength)); + EXPECT_EQ(1U, ranges_all.Size()); + EXPECT_TRUE(ranges_all.Get(0, range)); + EXPECT_EQ(range0_, range); + + CHttpRanges ranges_some; + EXPECT_TRUE(ranges_some.Parse(RANGES_START "2-", totalLength)); + EXPECT_EQ(1U, ranges_some.Size()); + EXPECT_TRUE(ranges_some.Get(0, range)); + EXPECT_EQ(range2_, range); +} + +TEST(TestHttpRanges, ParseFromEnd) +{ + const uint64_t totalLength = 5; + const CHttpRange range_1(totalLength - 1, totalLength - 1); + const CHttpRange range_3(totalLength - 3, totalLength - 1); + + CHttpRange range; + + CHttpRanges ranges_1; + EXPECT_TRUE(ranges_1.Parse(RANGES_START "-1", totalLength)); + EXPECT_EQ(1U, ranges_1.Size()); + EXPECT_TRUE(ranges_1.Get(0, range)); + EXPECT_EQ(range_1, range); + + CHttpRanges ranges_3; + EXPECT_TRUE(ranges_3.Parse(RANGES_START "-3", totalLength)); + EXPECT_EQ(1U, ranges_3.Size()); + EXPECT_TRUE(ranges_3.Get(0, range)); + EXPECT_EQ(range_3, range); +} + +TEST(TestHttpRanges, ParseSingle) +{ + const uint64_t totalLength = 5; + const CHttpRange range0_0(0, 0); + const CHttpRange range0_1(0, 1); + const CHttpRange range0_5(0, totalLength - 1); + const CHttpRange range1_1(1, 1); + const CHttpRange range1_3(1, 3); + const CHttpRange range3_4(3, 4); + const CHttpRange range4_4(4, 4); + + CHttpRange range; + + CHttpRanges ranges; + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_0, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-1", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_1, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-5", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_5, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "1-1", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range1_1, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "1-3", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range1_3, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "3-4", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range3_4, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "4-4", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range4_4, range); +} + +TEST(TestHttpRanges, ParseMulti) +{ + const uint64_t totalLength = 6; + const CHttpRange range0_0(0, 0); + const CHttpRange range0_1(0, 1); + const CHttpRange range1_3(1, 3); + const CHttpRange range2_2(2, 2); + const CHttpRange range4_5(4, 5); + const CHttpRange range5_5(5, 5); + + CHttpRange range; + + CHttpRanges ranges; + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,2-2", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range2_2, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,2-2,4-5", totalLength)); + EXPECT_EQ(3U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range2_2, range); + EXPECT_TRUE(ranges.Get(2, range)); + EXPECT_EQ(range4_5, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-1,5-5", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_1, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range5_5, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "1-3,5-5", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range1_3, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range5_5, range); +} + +TEST(TestHttpRanges, ParseOrderedNotOverlapping) +{ + const uint64_t totalLength = 5; + const CHttpRange range0_0(0, 0); + const CHttpRange range0_1(0, 1); + const CHttpRange range2_2(2, 2); + const CHttpRange range2_(2, totalLength - 1); + const CHttpRange range_1(totalLength - 1, totalLength - 1); + + CHttpRange range; + + CHttpRanges ranges; + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,-1", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range_1, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,2-2,-1", totalLength)); + EXPECT_EQ(3U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range2_2, range); + EXPECT_TRUE(ranges.Get(2, range)); + EXPECT_EQ(range_1, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,2-", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range2_, range); +} + +TEST(TestHttpRanges, ParseOrderedBackToBack) +{ + const uint64_t totalLength = 5; + const CHttpRange range0_1(0, 1); + const CHttpRange range0_2(0, 2); + const CHttpRange range1_2(1, 2); + const CHttpRange range0_3(0, 3); + const CHttpRange range4_4(4, 4); + const CHttpRange range0_4(0, 4); + const CHttpRange range3_4(3, 4); + + CHttpRange range; + + CHttpRanges ranges; + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,1-1", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_1, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,1-1,2-2", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_2, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,1-1,2-2,3-3", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_3, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,1-1,2-2,3-3,4-4", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_4, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,1-1,3-3,4-4", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_1, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range3_4, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "1-1,2-2,4-4", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range1_2, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range4_4, range); +} + +TEST(TestHttpRanges, ParseOrderedOverlapping) +{ + const uint64_t totalLength = 5; + const CHttpRange range0_0(0, 0); + const CHttpRange range0_1(0, 1); + const CHttpRange range0_2(0, 2); + const CHttpRange range0_3(0, 3); + const CHttpRange range0_4(0, 4); + const CHttpRange range2_4(2, 4); + + CHttpRange range; + + CHttpRanges ranges; + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,0-1", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_1, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,0-1,0-2", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_2, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,0-1,1-2", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_2, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,0-2,1-3", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_3, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-1,1-2,2-3,3-4", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_4, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-0,2-3,2-4,4-4", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range2_4, range); +} + +TEST(TestHttpRanges, ParseUnorderedNotOverlapping) +{ + const uint64_t totalLength = 5; + const CHttpRange range0_0(0, 0); + const CHttpRange range0_1(0, 1); + const CHttpRange range2_2(2, 2); + const CHttpRange range2_(2, totalLength - 1); + const CHttpRange range_1(totalLength - 1, totalLength - 1); + + CHttpRange range; + + CHttpRanges ranges; + EXPECT_TRUE(ranges.Parse(RANGES_START "-1,0-0", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range_1, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "2-2,-1,0-0", totalLength)); + EXPECT_EQ(3U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range2_2, range); + EXPECT_TRUE(ranges.Get(2, range)); + EXPECT_EQ(range_1, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "2-,0-0", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range2_, range); +} + +TEST(TestHttpRanges, ParseUnorderedBackToBack) +{ + const uint64_t totalLength = 5; + const CHttpRange range0_0(0, 0); + const CHttpRange range1_1(1, 1); + const CHttpRange range0_1(0, 1); + const CHttpRange range2_2(2, 2); + const CHttpRange range0_2(0, 2); + const CHttpRange range1_2(1, 2); + const CHttpRange range3_3(3, 3); + const CHttpRange range0_3(0, 3); + const CHttpRange range4_4(4, 4); + const CHttpRange range0_4(0, 4); + const CHttpRange range3_4(3, 4); + + CHttpRange range; + + CHttpRanges ranges; + EXPECT_TRUE(ranges.Parse(RANGES_START "1-1,0-0", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_1, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "1-1,0-0,2-2", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_2, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "2-2,1-1,3-3,0-0", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_3, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "4-4,1-1,0-0,2-2,3-3", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_4, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "3-3,0-0,4-4,1-1", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_1, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range3_4, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "4-4,1-1,2-2", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range1_2, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range4_4, range); +} + +TEST(TestHttpRanges, ParseUnorderedOverlapping) +{ + const uint64_t totalLength = 5; + const CHttpRange range0_0(0, 0); + const CHttpRange range0_1(0, 1); + const CHttpRange range0_2(0, 2); + const CHttpRange range0_3(0, 3); + const CHttpRange range0_4(0, 4); + const CHttpRange range2_4(2, 4); + + CHttpRange range; + + CHttpRanges ranges; + EXPECT_TRUE(ranges.Parse(RANGES_START "0-1,0-0", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_1, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-2,0-0,0-1", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_2, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-1,1-2,0-0", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_2, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "0-2,0-0,1-3", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_3, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "2-3,1-2,0-1,3-4", totalLength)); + EXPECT_EQ(1U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_4, range); + + EXPECT_TRUE(ranges.Parse(RANGES_START "4-4,0-0,2-4,2-3", totalLength)); + EXPECT_EQ(2U, ranges.Size()); + EXPECT_TRUE(ranges.Get(0, range)); + EXPECT_EQ(range0_0, range); + EXPECT_TRUE(ranges.Get(1, range)); + EXPECT_EQ(range2_4, range); +} diff --git a/xbmc/utils/test/TestHttpResponse.cpp b/xbmc/utils/test/TestHttpResponse.cpp new file mode 100644 index 0000000..1f66285 --- /dev/null +++ b/xbmc/utils/test/TestHttpResponse.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/HttpResponse.h" + +#include <gtest/gtest.h> + +TEST(TestHttpResponse, General) +{ + CHttpResponse a(HTTP::POST, HTTP::OK); + std::string response, content, refstr; + + a.AddHeader("date", "Sun, 01 Jul 2012 00:00:00 -0400"); + a.AddHeader("content-type", "text/html"); + content = "<html>\r\n" + " <body>\r\n" + " <h1>XBMC TestHttpResponse Page</h1>\r\n" + " <p>blah blah blah</p>\r\n" + " </body>\r\n" + "</html>\r\n"; + a.SetContent(content.c_str(), content.length()); + + response = a.Create();; + EXPECT_EQ((unsigned int)210, response.size()); + + refstr = "HTTP/1.1 200 OK\r\n" + "date: Sun, 01 Jul 2012 00:00:00 -0400\r\n" + "content-type: text/html\r\n" + "Content-Length: 106\r\n" + "\r\n" + "<html>\r\n" + " <body>\r\n" + " <h1>XBMC TestHttpResponse Page</h1>\r\n" + " <p>blah blah blah</p>\r\n" + " </body>\r\n" + "</html>\r\n"; + EXPECT_STREQ(refstr.c_str(), response.c_str()); +} diff --git a/xbmc/utils/test/TestJSONVariantParser.cpp b/xbmc/utils/test/TestJSONVariantParser.cpp new file mode 100644 index 0000000..b8556b0 --- /dev/null +++ b/xbmc/utils/test/TestJSONVariantParser.cpp @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/JSONVariantParser.h" +#include "utils/Variant.h" + +#include <gtest/gtest.h> + +TEST(TestJSONVariantParser, CannotParseNullptr) +{ + CVariant variant; + ASSERT_FALSE(CJSONVariantParser::Parse(nullptr, variant)); +} + +TEST(TestJSONVariantParser, CannotParseEmptyString) +{ + CVariant variant; + ASSERT_FALSE(CJSONVariantParser::Parse("", variant)); + ASSERT_FALSE(CJSONVariantParser::Parse(std::string(), variant)); +} + +TEST(TestJSONVariantParser, CannotParseInvalidJson) +{ + CVariant variant; + ASSERT_FALSE(CJSONVariantParser::Parse("{", variant)); + ASSERT_FALSE(CJSONVariantParser::Parse("}", variant)); + ASSERT_FALSE(CJSONVariantParser::Parse("[", variant)); + ASSERT_FALSE(CJSONVariantParser::Parse("]", variant)); + ASSERT_FALSE(CJSONVariantParser::Parse("foo", variant)); +} + +TEST(TestJSONVariantParser, CanParseNull) +{ + CVariant variant; + ASSERT_TRUE(CJSONVariantParser::Parse("null", variant)); + ASSERT_TRUE(variant.isNull()); +} + +TEST(TestJSONVariantParser, CanParseBoolean) +{ + CVariant variant; + ASSERT_TRUE(CJSONVariantParser::Parse("true", variant)); + ASSERT_TRUE(variant.isBoolean()); + ASSERT_TRUE(variant.asBoolean()); + + ASSERT_TRUE(CJSONVariantParser::Parse("false", variant)); + ASSERT_TRUE(variant.isBoolean()); + ASSERT_FALSE(variant.asBoolean()); +} + +TEST(TestJSONVariantParser, CanParseSignedInteger) +{ + CVariant variant; + ASSERT_TRUE(CJSONVariantParser::Parse("-1", variant)); + ASSERT_TRUE(variant.isInteger()); + ASSERT_EQ(-1, variant.asInteger()); +} + +TEST(TestJSONVariantParser, CanParseUnsignedInteger) +{ + CVariant variant; + ASSERT_TRUE(CJSONVariantParser::Parse("0", variant)); + ASSERT_TRUE(variant.isUnsignedInteger()); + ASSERT_EQ(0U, variant.asUnsignedInteger()); + + ASSERT_TRUE(CJSONVariantParser::Parse("1", variant)); + ASSERT_TRUE(variant.isUnsignedInteger()); + ASSERT_EQ(1U, variant.asUnsignedInteger()); +} + +TEST(TestJSONVariantParser, CanParseSignedInteger64) +{ + CVariant variant; + ASSERT_TRUE(CJSONVariantParser::Parse("-4294967296", variant)); + ASSERT_TRUE(variant.isInteger()); + ASSERT_EQ(-4294967296, variant.asInteger()); +} + +TEST(TestJSONVariantParser, CanParseUnsignedInteger64) +{ + CVariant variant; + ASSERT_TRUE(CJSONVariantParser::Parse("4294967296", variant)); + ASSERT_TRUE(variant.isUnsignedInteger()); + ASSERT_EQ(4294967296U, variant.asUnsignedInteger()); +} + +TEST(TestJSONVariantParser, CanParseDouble) +{ + CVariant variant; + ASSERT_TRUE(CJSONVariantParser::Parse("0.0", variant)); + ASSERT_TRUE(variant.isDouble()); + ASSERT_EQ(0.0, variant.asDouble()); + + ASSERT_TRUE(CJSONVariantParser::Parse("1.0", variant)); + ASSERT_TRUE(variant.isDouble()); + ASSERT_EQ(1.0, variant.asDouble()); + + ASSERT_TRUE(CJSONVariantParser::Parse("-1.0", variant)); + ASSERT_TRUE(variant.isDouble()); + ASSERT_EQ(-1.0, variant.asDouble()); +} + +TEST(TestJSONVariantParser, CanParseString) +{ + CVariant variant; + ASSERT_TRUE(CJSONVariantParser::Parse("\"\"", variant)); + ASSERT_TRUE(variant.isString()); + ASSERT_TRUE(variant.empty()); + + ASSERT_TRUE(CJSONVariantParser::Parse("\"foo\"", variant)); + ASSERT_TRUE(variant.isString()); + ASSERT_STREQ("foo", variant.asString().c_str()); + + ASSERT_TRUE(CJSONVariantParser::Parse("\"foo bar\"", variant)); + ASSERT_TRUE(variant.isString()); + ASSERT_STREQ("foo bar", variant.asString().c_str()); +} + +TEST(TestJSONVariantParser, CanParseObject) +{ + CVariant variant; + ASSERT_TRUE(CJSONVariantParser::Parse("{}", variant)); + ASSERT_TRUE(variant.isObject()); + ASSERT_TRUE(variant.empty()); + + variant.clear(); + ASSERT_TRUE(CJSONVariantParser::Parse("{ \"foo\": \"bar\" }", variant)); + ASSERT_TRUE(variant.isObject()); + ASSERT_TRUE(variant.isMember("foo")); + ASSERT_TRUE(variant["foo"].isString()); + ASSERT_STREQ("bar", variant["foo"].asString().c_str()); + + variant.clear(); + ASSERT_TRUE(CJSONVariantParser::Parse("{ \"foo\": \"bar\", \"bar\": true }", variant)); + ASSERT_TRUE(variant.isObject()); + ASSERT_TRUE(variant.isMember("foo")); + ASSERT_TRUE(variant["foo"].isString()); + ASSERT_STREQ("bar", variant["foo"].asString().c_str()); + ASSERT_TRUE(variant.isMember("bar")); + ASSERT_TRUE(variant["bar"].isBoolean()); + ASSERT_TRUE(variant["bar"].asBoolean()); + + variant.clear(); + ASSERT_TRUE(CJSONVariantParser::Parse("{ \"foo\": { \"sub-foo\": \"bar\" } }", variant)); + ASSERT_TRUE(variant.isObject()); + ASSERT_TRUE(variant.isMember("foo")); + ASSERT_TRUE(variant["foo"].isObject()); + ASSERT_TRUE(variant["foo"].isMember("sub-foo")); + ASSERT_TRUE(variant["foo"]["sub-foo"].isString()); + ASSERT_STREQ("bar", variant["foo"]["sub-foo"].asString().c_str()); +} + +TEST(TestJSONVariantParser, CanParseArray) +{ + CVariant variant; + ASSERT_TRUE(CJSONVariantParser::Parse("[]", variant)); + ASSERT_TRUE(variant.isArray()); + ASSERT_TRUE(variant.empty()); + + variant.clear(); + ASSERT_TRUE(CJSONVariantParser::Parse("[ true ]", variant)); + ASSERT_TRUE(variant.isArray()); + ASSERT_EQ(1U, variant.size()); + ASSERT_TRUE(variant[0].isBoolean()); + ASSERT_TRUE(variant[0].asBoolean()); + + variant.clear(); + ASSERT_TRUE(CJSONVariantParser::Parse("[ true, \"foo\" ]", variant)); + ASSERT_TRUE(variant.isArray()); + ASSERT_EQ(2U, variant.size()); + ASSERT_TRUE(variant[0].isBoolean()); + ASSERT_TRUE(variant[0].asBoolean()); + ASSERT_TRUE(variant[1].isString()); + ASSERT_STREQ("foo", variant[1].asString().c_str()); + + variant.clear(); + ASSERT_TRUE(CJSONVariantParser::Parse("[ { \"foo\": \"bar\" } ]", variant)); + ASSERT_TRUE(variant.isArray()); + ASSERT_EQ(1U, variant.size()); + ASSERT_TRUE(variant[0].isObject()); + ASSERT_TRUE(variant[0].isMember("foo")); + ASSERT_TRUE(variant[0]["foo"].isString()); + ASSERT_STREQ("bar", variant[0]["foo"].asString().c_str()); +} diff --git a/xbmc/utils/test/TestJSONVariantWriter.cpp b/xbmc/utils/test/TestJSONVariantWriter.cpp new file mode 100644 index 0000000..0772a4d --- /dev/null +++ b/xbmc/utils/test/TestJSONVariantWriter.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/JSONVariantWriter.h" +#include "utils/Variant.h" + +#include <gtest/gtest.h> + +TEST(TestJSONVariantWriter, CanWriteNull) +{ + CVariant variant; + std::string str; + + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("null", str.c_str()); +} + +TEST(TestJSONVariantWriter, CanWriteBoolean) +{ + CVariant variant(true); + std::string str; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("true", str.c_str()); + + variant = false; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("false", str.c_str()); +} + +TEST(TestJSONVariantWriter, CanWriteSignedInteger) +{ + CVariant variant(-1); + std::string str; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("-1", str.c_str()); +} + +TEST(TestJSONVariantWriter, CanWriteUnsignedInteger) +{ + CVariant variant(0); + std::string str; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("0", str.c_str()); + + variant = 1; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("1", str.c_str()); +} + +TEST(TestJSONVariantWriter, CanWriteSignedInteger64) +{ + CVariant variant(static_cast<int64_t>(-4294967296LL)); + std::string str; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("-4294967296", str.c_str()); +} + +TEST(TestJSONVariantWriter, CanWriteUnsignedInteger64) +{ + CVariant variant(static_cast<int64_t>(4294967296LL)); + std::string str; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("4294967296", str.c_str()); +} + +TEST(TestJSONVariantWriter, CanWriteDouble) +{ + CVariant variant(0.0); + std::string str; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("0.0", str.c_str()); + + variant = 1.0; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("1.0", str.c_str()); + + variant = -1.0; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("-1.0", str.c_str()); +} + +TEST(TestJSONVariantWriter, CanWriteString) +{ + CVariant variant(""); + std::string str; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("\"\"", str.c_str()); + + variant = "foo"; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("\"foo\"", str.c_str()); + + variant = "foo bar"; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("\"foo bar\"", str.c_str()); +} + +TEST(TestJSONVariantWriter, CanWriteObject) +{ + CVariant variant(CVariant::VariantTypeObject); + std::string str; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("{}", str.c_str()); + + variant.clear(); + variant["foo"] = "bar"; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("{\n\t\"foo\": \"bar\"\n}", str.c_str()); + + variant.clear(); + variant["foo"] = "bar"; + variant["bar"] = true; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("{\n\t\"bar\": true,\n\t\"foo\": \"bar\"\n}", str.c_str()); + + variant.clear(); + variant["foo"]["sub-foo"] = "bar"; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("{\n\t\"foo\": {\n\t\t\"sub-foo\": \"bar\"\n\t}\n}", str.c_str()); +} + +TEST(TestJSONVariantWriter, CanWriteArray) +{ + CVariant variant(CVariant::VariantTypeArray); + std::string str; + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("[]", str.c_str()); + + variant.clear(); + variant.push_back(true); + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("[\n\ttrue\n]", str.c_str()); + + variant.clear(); + variant.push_back(true); + variant.push_back("foo"); + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("[\n\ttrue,\n\t\"foo\"\n]", str.c_str()); + + variant.clear(); + CVariant obj(CVariant::VariantTypeObject); + obj["foo"] = "bar"; + variant.push_back(obj); + ASSERT_TRUE(CJSONVariantWriter::Write(variant, str, false)); + ASSERT_STREQ("[\n\t{\n\t\t\"foo\": \"bar\"\n\t}\n]", str.c_str()); +} diff --git a/xbmc/utils/test/TestJobManager.cpp b/xbmc/utils/test/TestJobManager.cpp new file mode 100644 index 0000000..86f0af9 --- /dev/null +++ b/xbmc/utils/test/TestJobManager.cpp @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "ServiceBroker.h" +#include "test/MtTestUtils.h" +#include "utils/Job.h" +#include "utils/JobManager.h" +#include "utils/XTimeUtils.h" + +#include <atomic> +#include <mutex> + +#include <gtest/gtest.h> + +using namespace ConditionPoll; + +struct Flags +{ + std::atomic<bool> lingerAtWork{true}; + std::atomic<bool> started{false}; + std::atomic<bool> finished{false}; + std::atomic<bool> wasCanceled{false}; +}; + +class DummyJob : public CJob +{ + Flags* m_flags; +public: + inline DummyJob(Flags* flags) : m_flags(flags) + { + } + + bool DoWork() override + { + m_flags->started = true; + while (m_flags->lingerAtWork) + std::this_thread::yield(); + + if (ShouldCancel(0,0)) + m_flags->wasCanceled = true; + + m_flags->finished = true; + return true; + } +}; + +class ReallyDumbJob : public CJob +{ + Flags* m_flags; +public: + inline ReallyDumbJob(Flags* flags) : m_flags(flags) {} + + bool DoWork() override + { + m_flags->finished = true; + return true; + } +}; + +class TestJobManager : public testing::Test +{ +protected: + TestJobManager() { CServiceBroker::RegisterJobManager(std::make_shared<CJobManager>()); } + + ~TestJobManager() override + { + /* Always cancel jobs test completion */ + CServiceBroker::GetJobManager()->CancelJobs(); + CServiceBroker::GetJobManager()->Restart(); + CServiceBroker::UnregisterJobManager(); + } +}; + +TEST_F(TestJobManager, AddJob) +{ + Flags* flags = new Flags(); + ReallyDumbJob* job = new ReallyDumbJob(flags); + CServiceBroker::GetJobManager()->AddJob(job, nullptr); + ASSERT_TRUE(poll([flags]() -> bool { return flags->finished; })); + delete flags; +} + +TEST_F(TestJobManager, CancelJob) +{ + unsigned int id; + Flags* flags = new Flags(); + DummyJob* job = new DummyJob(flags); + id = CServiceBroker::GetJobManager()->AddJob(job, nullptr); + + // wait for the worker thread to be entered + ASSERT_TRUE(poll([flags]() -> bool { return flags->started; })); + + // cancel the job + CServiceBroker::GetJobManager()->CancelJob(id); + + // let the worker thread continue + flags->lingerAtWork = false; + + // make sure the job finished. + ASSERT_TRUE(poll([flags]() -> bool { return flags->finished; })); + + // ... and that it was canceled. + EXPECT_TRUE(flags->wasCanceled); + delete flags; +} + +namespace +{ +struct JobControlPackage +{ + JobControlPackage() + { + // We're not ready to wait yet + jobCreatedMutex.lock(); + } + + ~JobControlPackage() + { + jobCreatedMutex.unlock(); + } + + bool ready = false; + XbmcThreads::ConditionVariable jobCreatedCond; + CCriticalSection jobCreatedMutex; +}; + +class BroadcastingJob : + public CJob +{ +public: + + BroadcastingJob(JobControlPackage &package) : + m_package(package), + m_finish(false) + { + } + + void FinishAndStopBlocking() + { + std::unique_lock<CCriticalSection> lock(m_blockMutex); + + m_finish = true; + m_block.notifyAll(); + } + + const char * GetType() const override + { + return "BroadcastingJob"; + } + + bool DoWork() override + { + { + std::unique_lock<CCriticalSection> lock(m_package.jobCreatedMutex); + + m_package.ready = true; + m_package.jobCreatedCond.notifyAll(); + } + + std::unique_lock<CCriticalSection> blockLock(m_blockMutex); + + // Block until we're told to go away + while (!m_finish) + m_block.wait(m_blockMutex); + return true; + } + +private: + + JobControlPackage &m_package; + + XbmcThreads::ConditionVariable m_block; + CCriticalSection m_blockMutex; + bool m_finish; +}; + +BroadcastingJob * +WaitForJobToStartProcessing(CJob::PRIORITY priority, JobControlPackage &package) +{ + BroadcastingJob* job = new BroadcastingJob(package); + CServiceBroker::GetJobManager()->AddJob(job, nullptr, priority); + + // We're now ready to wait, wait and then unblock once ready + while (!package.ready) + package.jobCreatedCond.wait(package.jobCreatedMutex); + + return job; +} +} + +TEST_F(TestJobManager, PauseLowPriorityJob) +{ + JobControlPackage package; + BroadcastingJob *job (WaitForJobToStartProcessing(CJob::PRIORITY_LOW_PAUSABLE, package)); + + EXPECT_TRUE(CServiceBroker::GetJobManager()->IsProcessing(CJob::PRIORITY_LOW_PAUSABLE)); + CServiceBroker::GetJobManager()->PauseJobs(); + EXPECT_FALSE(CServiceBroker::GetJobManager()->IsProcessing(CJob::PRIORITY_LOW_PAUSABLE)); + CServiceBroker::GetJobManager()->UnPauseJobs(); + EXPECT_TRUE(CServiceBroker::GetJobManager()->IsProcessing(CJob::PRIORITY_LOW_PAUSABLE)); + + job->FinishAndStopBlocking(); +} + +TEST_F(TestJobManager, IsProcessing) +{ + JobControlPackage package; + BroadcastingJob *job (WaitForJobToStartProcessing(CJob::PRIORITY_LOW_PAUSABLE, package)); + + EXPECT_EQ(0, CServiceBroker::GetJobManager()->IsProcessing("")); + + job->FinishAndStopBlocking(); +} diff --git a/xbmc/utils/test/TestLabelFormatter.cpp b/xbmc/utils/test/TestLabelFormatter.cpp new file mode 100644 index 0000000..633e89a --- /dev/null +++ b/xbmc/utils/test/TestLabelFormatter.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "FileItem.h" +#include "ServiceBroker.h" +#include "filesystem/File.h" +#include "settings/Settings.h" +#include "settings/SettingsComponent.h" +#include "test/TestUtils.h" +#include "utils/LabelFormatter.h" + +#include <gtest/gtest.h> + +/* Set default settings used by CLabelFormatter. */ +class TestLabelFormatter : public testing::Test +{ +protected: + TestLabelFormatter() = default; + + ~TestLabelFormatter() override + { + CServiceBroker::GetSettingsComponent()->GetSettings()->Unload(); + } +}; + +TEST_F(TestLabelFormatter, FormatLabel) +{ + XFILE::CFile *tmpfile; + std::string tmpfilepath; + LABEL_MASKS labelMasks; + CLabelFormatter formatter("", labelMasks.m_strLabel2File); + + ASSERT_NE(nullptr, (tmpfile = XBMC_CREATETEMPFILE(""))); + tmpfilepath = XBMC_TEMPFILEPATH(tmpfile); + + CFileItemPtr item(new CFileItem(tmpfilepath)); + item->SetPath(tmpfilepath); + item->m_bIsFolder = false; + item->Select(true); + + formatter.FormatLabel(item.get()); + + EXPECT_TRUE(XBMC_DELETETEMPFILE(tmpfile)); +} + +TEST_F(TestLabelFormatter, FormatLabel2) +{ + XFILE::CFile *tmpfile; + std::string tmpfilepath; + LABEL_MASKS labelMasks; + CLabelFormatter formatter("", labelMasks.m_strLabel2File); + + ASSERT_NE(nullptr, (tmpfile = XBMC_CREATETEMPFILE(""))); + tmpfilepath = XBMC_TEMPFILEPATH(tmpfile); + + CFileItemPtr item(new CFileItem(tmpfilepath)); + item->SetPath(tmpfilepath); + item->m_bIsFolder = false; + item->Select(true); + + formatter.FormatLabel2(item.get()); + + EXPECT_TRUE(XBMC_DELETETEMPFILE(tmpfile)); +} diff --git a/xbmc/utils/test/TestLangCodeExpander.cpp b/xbmc/utils/test/TestLangCodeExpander.cpp new file mode 100644 index 0000000..7a6dde1 --- /dev/null +++ b/xbmc/utils/test/TestLangCodeExpander.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/LangCodeExpander.h" + +#include <gtest/gtest.h> + +TEST(TestLangCodeExpander, ConvertISO6391ToISO6392B) +{ + std::string refstr, varstr; + + refstr = "eng"; + g_LangCodeExpander.ConvertISO6391ToISO6392B("en", varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestLangCodeExpander, ConvertToISO6392B) +{ + std::string refstr, varstr; + + refstr = "eng"; + g_LangCodeExpander.ConvertToISO6392B("en", varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} diff --git a/xbmc/utils/test/TestLocale.cpp b/xbmc/utils/test/TestLocale.cpp new file mode 100644 index 0000000..f5193ed --- /dev/null +++ b/xbmc/utils/test/TestLocale.cpp @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/Locale.h" +#include "utils/StringUtils.h" + +#include <gtest/gtest.h> + +static const std::string TerritorySeparator = "_"; +static const std::string CodesetSeparator = "."; +static const std::string ModifierSeparator = "@"; + +static const std::string LanguageCodeEnglish = "en"; +static const std::string TerritoryCodeBritain = "GB"; +static const std::string CodesetUtf8 = "UTF-8"; +static const std::string ModifierLatin = "latin"; + +TEST(TestLocale, DefaultLocale) +{ + CLocale locale; + ASSERT_FALSE(locale.IsValid()); + ASSERT_STREQ("", locale.GetLanguageCode().c_str()); + ASSERT_STREQ("", locale.GetTerritoryCode().c_str()); + ASSERT_STREQ("", locale.GetCodeset().c_str()); + ASSERT_STREQ("", locale.GetModifier().c_str()); + ASSERT_STREQ("", locale.ToString().c_str()); +} + +TEST(TestLocale, LanguageLocale) +{ + CLocale locale(LanguageCodeEnglish); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ("", locale.GetTerritoryCode().c_str()); + ASSERT_STREQ("", locale.GetCodeset().c_str()); + ASSERT_STREQ("", locale.GetModifier().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, LanguageTerritoryLocale) +{ + const std::string strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain; + std::string strLocaleLC = strLocale; + StringUtils::ToLower(strLocaleLC); + + CLocale locale(LanguageCodeEnglish, TerritoryCodeBritain); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ(TerritoryCodeBritain.c_str(), locale.GetTerritoryCode().c_str()); + ASSERT_STREQ("", locale.GetCodeset().c_str()); + ASSERT_STREQ("", locale.GetModifier().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, LanguageCodesetLocale) +{ + const std::string strLocale = LanguageCodeEnglish + CodesetSeparator + CodesetUtf8; + std::string strLocaleLC = strLocale; + StringUtils::ToLower(strLocaleLC); + + CLocale locale(LanguageCodeEnglish, "", CodesetUtf8); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ("", locale.GetTerritoryCode().c_str()); + ASSERT_STREQ(CodesetUtf8.c_str(), locale.GetCodeset().c_str()); + ASSERT_STREQ("", locale.GetModifier().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, LanguageModifierLocale) +{ + const std::string strLocale = LanguageCodeEnglish + ModifierSeparator + ModifierLatin; + std::string strLocaleLC = strLocale; + StringUtils::ToLower(strLocaleLC); + + CLocale locale(LanguageCodeEnglish, "", "", ModifierLatin); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ("", locale.GetTerritoryCode().c_str()); + ASSERT_STREQ("", locale.GetCodeset().c_str()); + ASSERT_STREQ(ModifierLatin.c_str(), locale.GetModifier().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, LanguageTerritoryCodesetLocale) +{ + const std::string strLocaleShort = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain; + std::string strLocaleShortLC = strLocaleShort; + StringUtils::ToLower(strLocaleShortLC); + const std::string strLocale = strLocaleShort + CodesetSeparator + CodesetUtf8; + std::string strLocaleLC = strLocale; + StringUtils::ToLower(strLocaleLC); + + CLocale locale(LanguageCodeEnglish, TerritoryCodeBritain, CodesetUtf8); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ(TerritoryCodeBritain.c_str(), locale.GetTerritoryCode().c_str()); + ASSERT_STREQ(CodesetUtf8.c_str(), locale.GetCodeset().c_str()); + ASSERT_STREQ("", locale.GetModifier().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(strLocaleShort.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(strLocaleShortLC.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, LanguageTerritoryModifierLocale) +{ + const std::string strLocaleShort = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain; + std::string strLocaleShortLC = strLocaleShort; + StringUtils::ToLower(strLocaleShortLC); + const std::string strLocale = strLocaleShort + ModifierSeparator + ModifierLatin; + std::string strLocaleLC = strLocale; + StringUtils::ToLower(strLocaleLC); + + CLocale locale(LanguageCodeEnglish, TerritoryCodeBritain, "", ModifierLatin); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ(TerritoryCodeBritain.c_str(), locale.GetTerritoryCode().c_str()); + ASSERT_STREQ("", locale.GetCodeset().c_str()); + ASSERT_STREQ(ModifierLatin.c_str(), locale.GetModifier().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(strLocaleShort.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(strLocaleShortLC.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, LanguageTerritoryCodesetModifierLocale) +{ + const std::string strLocaleShort = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain; + std::string strLocaleShortLC = strLocaleShort; + StringUtils::ToLower(strLocaleShortLC); + const std::string strLocale = strLocaleShort + CodesetSeparator + CodesetUtf8 + ModifierSeparator + ModifierLatin; + std::string strLocaleLC = strLocale; + StringUtils::ToLower(strLocaleLC); + + CLocale locale(LanguageCodeEnglish, TerritoryCodeBritain, CodesetUtf8, ModifierLatin); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ(TerritoryCodeBritain.c_str(), locale.GetTerritoryCode().c_str()); + ASSERT_STREQ(CodesetUtf8.c_str(), locale.GetCodeset().c_str()); + ASSERT_STREQ(ModifierLatin.c_str(), locale.GetModifier().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(strLocaleShort.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(strLocaleShortLC.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, FullStringLocale) +{ + const std::string strLocaleShort = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain; + std::string strLocaleShortLC = strLocaleShort; + StringUtils::ToLower(strLocaleShortLC); + const std::string strLocale = strLocaleShort + CodesetSeparator + CodesetUtf8 + ModifierSeparator + ModifierLatin; + std::string strLocaleLC = strLocale; + StringUtils::ToLower(strLocaleLC); + + CLocale locale(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(LanguageCodeEnglish.c_str(), locale.GetLanguageCode().c_str()); + ASSERT_STREQ(TerritoryCodeBritain.c_str(), locale.GetTerritoryCode().c_str()); + ASSERT_STREQ(CodesetUtf8.c_str(), locale.GetCodeset().c_str()); + ASSERT_STREQ(ModifierLatin.c_str(), locale.GetModifier().c_str()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + ASSERT_STREQ(strLocaleLC.c_str(), locale.ToStringLC().c_str()); + ASSERT_STREQ(strLocaleShort.c_str(), locale.ToShortString().c_str()); + ASSERT_STREQ(strLocaleShortLC.c_str(), locale.ToShortStringLC().c_str()); +} + +TEST(TestLocale, FromString) +{ + std::string strLocale = ""; + CLocale locale = CLocale::FromString(strLocale); + ASSERT_FALSE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + + strLocale = LanguageCodeEnglish; + locale = CLocale::FromString(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain; + locale = CLocale::FromString(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + + strLocale = LanguageCodeEnglish + CodesetSeparator + CodesetUtf8; + locale = CLocale::FromString(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + + strLocale = LanguageCodeEnglish + ModifierSeparator + ModifierLatin; + locale = CLocale::FromString(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain + CodesetSeparator + CodesetUtf8; + locale = CLocale::FromString(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain + ModifierSeparator + ModifierLatin; + locale = CLocale::FromString(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); + + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain + CodesetSeparator + CodesetUtf8 + ModifierSeparator + ModifierLatin; + locale = CLocale::FromString(strLocale); + ASSERT_TRUE(locale.IsValid()); + ASSERT_STREQ(strLocale.c_str(), locale.ToString().c_str()); +} + +TEST(TestLocale, EmptyLocale) +{ + ASSERT_FALSE(CLocale::Empty.IsValid()); + ASSERT_STREQ("", CLocale::Empty.GetLanguageCode().c_str()); + ASSERT_STREQ("", CLocale::Empty.GetTerritoryCode().c_str()); + ASSERT_STREQ("", CLocale::Empty.GetCodeset().c_str()); + ASSERT_STREQ("", CLocale::Empty.GetModifier().c_str()); + ASSERT_STREQ("", CLocale::Empty.ToString().c_str()); +} + +TEST(TestLocale, Equals) +{ + std::string strLocale = ""; + CLocale locale; + ASSERT_TRUE(locale.Equals(strLocale)); + + locale = CLocale(LanguageCodeEnglish); + strLocale = LanguageCodeEnglish; + ASSERT_TRUE(locale.Equals(strLocale)); + + locale = CLocale(LanguageCodeEnglish, TerritoryCodeBritain); + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain; + ASSERT_TRUE(locale.Equals(strLocale)); + + locale = CLocale(LanguageCodeEnglish, "", CodesetUtf8); + strLocale = LanguageCodeEnglish + CodesetSeparator + CodesetUtf8; + ASSERT_TRUE(locale.Equals(strLocale)); + + locale = CLocale(LanguageCodeEnglish, "", "", ModifierLatin); + strLocale = LanguageCodeEnglish + ModifierSeparator + ModifierLatin; + ASSERT_TRUE(locale.Equals(strLocale)); + + locale = CLocale(LanguageCodeEnglish, TerritoryCodeBritain, CodesetUtf8); + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain + CodesetSeparator + CodesetUtf8; + ASSERT_TRUE(locale.Equals(strLocale)); + + locale = CLocale(LanguageCodeEnglish, TerritoryCodeBritain, "", ModifierLatin); + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain + ModifierSeparator + ModifierLatin; + ASSERT_TRUE(locale.Equals(strLocale)); + + locale = CLocale(LanguageCodeEnglish, TerritoryCodeBritain, CodesetUtf8, ModifierLatin); + strLocale = LanguageCodeEnglish + TerritorySeparator + TerritoryCodeBritain + CodesetSeparator + CodesetUtf8 + ModifierSeparator + ModifierLatin; + ASSERT_TRUE(locale.Equals(strLocale)); +} diff --git a/xbmc/utils/test/TestMathUtils.cpp b/xbmc/utils/test/TestMathUtils.cpp new file mode 100644 index 0000000..d60cc3f --- /dev/null +++ b/xbmc/utils/test/TestMathUtils.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/MathUtils.h" + +#include <gtest/gtest.h> + +TEST(TestMathUtils, round_int) +{ + int refval, varval, i; + + for (i = -8; i < 8; ++i) + { + double d = 0.25*i; + refval = (i < 0) ? (i - 1) / 4 : (i + 2) / 4; + varval = MathUtils::round_int(d); + EXPECT_EQ(refval, varval); + } +} + +TEST(TestMathUtils, truncate_int) +{ + int refval, varval, i; + + for (i = -8; i < 8; ++i) + { + double d = 0.25*i; + refval = i / 4; + varval = MathUtils::truncate_int(d); + EXPECT_EQ(refval, varval); + } +} + +TEST(TestMathUtils, abs) +{ + int64_t refval, varval; + + refval = 5; + varval = MathUtils::abs(-5); + EXPECT_EQ(refval, varval); +} + +TEST(TestMathUtils, bitcount) +{ + unsigned refval, varval; + + refval = 10; + varval = MathUtils::bitcount(0x03FF); + EXPECT_EQ(refval, varval); + + refval = 8; + varval = MathUtils::bitcount(0x2AD5); + EXPECT_EQ(refval, varval); +} diff --git a/xbmc/utils/test/TestMime.cpp b/xbmc/utils/test/TestMime.cpp new file mode 100644 index 0000000..7ef82c3 --- /dev/null +++ b/xbmc/utils/test/TestMime.cpp @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "FileItem.h" +#include "utils/Mime.h" + +#include <gtest/gtest.h> + +TEST(TestMime, GetMimeType_string) +{ + EXPECT_STREQ("video/avi", CMime::GetMimeType("avi").c_str()); + EXPECT_STRNE("video/x-msvideo", CMime::GetMimeType("avi").c_str()); + EXPECT_STRNE("video/avi", CMime::GetMimeType("xvid").c_str()); +} + +TEST(TestMime, GetMimeType_CFileItem) +{ + std::string refstr, varstr; + CFileItem item("testfile.mp4", false); + + refstr = "video/mp4"; + varstr = CMime::GetMimeType(item); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} diff --git a/xbmc/utils/test/TestPOUtils.cpp b/xbmc/utils/test/TestPOUtils.cpp new file mode 100644 index 0000000..5808c31 --- /dev/null +++ b/xbmc/utils/test/TestPOUtils.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "test/TestUtils.h" +#include "utils/POUtils.h" + +#include <gtest/gtest.h> + + +TEST(TestPOUtils, General) +{ + CPODocument a; + + EXPECT_TRUE(a.LoadFile(XBMC_REF_FILE_PATH("xbmc/utils/test/data/language/Spanish/strings.po"))); + + EXPECT_TRUE(a.GetNextEntry()); + EXPECT_EQ(ID_FOUND, a.GetEntryType()); + EXPECT_EQ((uint32_t)0, a.GetEntryID()); + a.ParseEntry(false); + EXPECT_STREQ("", a.GetMsgctxt().c_str()); + EXPECT_STREQ("Programs", a.GetMsgid().c_str()); + EXPECT_STREQ("Programas", a.GetMsgstr().c_str()); + EXPECT_STREQ("", a.GetPlurMsgstr(0).c_str()); + + EXPECT_TRUE(a.GetNextEntry()); + EXPECT_EQ(ID_FOUND, a.GetEntryType()); + EXPECT_EQ((uint32_t)1, a.GetEntryID()); + a.ParseEntry(false); + EXPECT_STREQ("", a.GetMsgctxt().c_str()); + EXPECT_STREQ("Pictures", a.GetMsgid().c_str()); + EXPECT_STREQ("Imágenes", a.GetMsgstr().c_str()); + EXPECT_STREQ("", a.GetPlurMsgstr(0).c_str()); + + EXPECT_TRUE(a.GetNextEntry()); + EXPECT_EQ(ID_FOUND, a.GetEntryType()); + EXPECT_EQ((uint32_t)2, a.GetEntryID()); + a.ParseEntry(false); + EXPECT_STREQ("", a.GetMsgctxt().c_str()); + EXPECT_STREQ("Music", a.GetMsgid().c_str()); + EXPECT_STREQ("Música", a.GetMsgstr().c_str()); + EXPECT_STREQ("", a.GetPlurMsgstr(0).c_str()); +} diff --git a/xbmc/utils/test/TestRegExp.cpp b/xbmc/utils/test/TestRegExp.cpp new file mode 100644 index 0000000..1cd3939 --- /dev/null +++ b/xbmc/utils/test/TestRegExp.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +/** @todo gtest/gtest.h needs to come in before utils/RegExp.h. + * Investigate why. + */ +#include "CompileInfo.h" +#include "ServiceBroker.h" +#include "filesystem/File.h" +#include "filesystem/SpecialProtocol.h" +#include "utils/RegExp.h" +#include "utils/StringUtils.h" +#include "utils/log.h" + +#include <gtest/gtest.h> + +TEST(TestRegExp, RegFind) +{ + CRegExp regex; + + EXPECT_TRUE(regex.RegComp("^Test.*")); + EXPECT_EQ(0, regex.RegFind("Test string.")); + + EXPECT_TRUE(regex.RegComp("^string.*")); + EXPECT_EQ(-1, regex.RegFind("Test string.")); +} + +TEST(TestRegExp, GetReplaceString) +{ + CRegExp regex; + + EXPECT_TRUE(regex.RegComp("^(Test)\\s*(.*)\\.")); + EXPECT_EQ(0, regex.RegFind("Test string.")); + EXPECT_STREQ("string", regex.GetReplaceString("\\2").c_str()); +} + +TEST(TestRegExp, GetFindLen) +{ + CRegExp regex; + + EXPECT_TRUE(regex.RegComp("^(Test)\\s*(.*)\\.")); + EXPECT_EQ(0, regex.RegFind("Test string.")); + EXPECT_EQ(12, regex.GetFindLen()); +} + +TEST(TestRegExp, GetSubCount) +{ + CRegExp regex; + + EXPECT_TRUE(regex.RegComp("^(Test)\\s*(.*)\\.")); + EXPECT_EQ(0, regex.RegFind("Test string.")); + EXPECT_EQ(2, regex.GetSubCount()); +} + +TEST(TestRegExp, GetSubStart) +{ + CRegExp regex; + + EXPECT_TRUE(regex.RegComp("^(Test)\\s*(.*)\\.")); + EXPECT_EQ(0, regex.RegFind("Test string.")); + EXPECT_EQ(0, regex.GetSubStart(0)); + EXPECT_EQ(0, regex.GetSubStart(1)); + EXPECT_EQ(5, regex.GetSubStart(2)); +} + +TEST(TestRegExp, GetCaptureTotal) +{ + CRegExp regex; + + EXPECT_TRUE(regex.RegComp("^(Test)\\s*(.*)\\.")); + EXPECT_EQ(0, regex.RegFind("Test string.")); + EXPECT_EQ(2, regex.GetCaptureTotal()); +} + +TEST(TestRegExp, GetMatch) +{ + CRegExp regex; + + EXPECT_TRUE(regex.RegComp("^(Test)\\s*(.*)\\.")); + EXPECT_EQ(0, regex.RegFind("Test string.")); + EXPECT_STREQ("Test string.", regex.GetMatch(0).c_str()); + EXPECT_STREQ("Test", regex.GetMatch(1).c_str()); + EXPECT_STREQ("string", regex.GetMatch(2).c_str()); +} + +TEST(TestRegExp, GetPattern) +{ + CRegExp regex; + + EXPECT_TRUE(regex.RegComp("^(Test)\\s*(.*)\\.")); + EXPECT_STREQ("^(Test)\\s*(.*)\\.", regex.GetPattern().c_str()); +} + +TEST(TestRegExp, GetNamedSubPattern) +{ + CRegExp regex; + std::string match; + + EXPECT_TRUE(regex.RegComp("^(?<first>Test)\\s*(?<second>.*)\\.")); + EXPECT_EQ(0, regex.RegFind("Test string.")); + EXPECT_TRUE(regex.GetNamedSubPattern("first", match)); + EXPECT_STREQ("Test", match.c_str()); + EXPECT_TRUE(regex.GetNamedSubPattern("second", match)); + EXPECT_STREQ("string", match.c_str()); +} + +TEST(TestRegExp, operatorEqual) +{ + CRegExp regex, regexcopy; + std::string match; + + EXPECT_TRUE(regex.RegComp("^(?<first>Test)\\s*(?<second>.*)\\.")); + regexcopy = regex; + EXPECT_EQ(0, regexcopy.RegFind("Test string.")); + EXPECT_TRUE(regexcopy.GetNamedSubPattern("first", match)); + EXPECT_STREQ("Test", match.c_str()); + EXPECT_TRUE(regexcopy.GetNamedSubPattern("second", match)); + EXPECT_STREQ("string", match.c_str()); +} + +class TestRegExpLog : public testing::Test +{ +protected: + TestRegExpLog() = default; + ~TestRegExpLog() override { CServiceBroker::GetLogging().Deinitialize(); } +}; + +TEST_F(TestRegExpLog, DumpOvector) +{ + CRegExp regex; + std::string logfile, logstring; + char buf[100]; + ssize_t bytesread; + XFILE::CFile file; + + std::string appName = CCompileInfo::GetAppName(); + StringUtils::ToLower(appName); + logfile = CSpecialProtocol::TranslatePath("special://temp/") + appName + ".log"; + CServiceBroker::GetLogging().Initialize( + CSpecialProtocol::TranslatePath("special://temp/").c_str()); + EXPECT_TRUE(XFILE::CFile::Exists(logfile)); + + EXPECT_TRUE(regex.RegComp("^(?<first>Test)\\s*(?<second>.*)\\.")); + EXPECT_EQ(0, regex.RegFind("Test string.")); + regex.DumpOvector(LOGDEBUG); + CServiceBroker::GetLogging().Deinitialize(); + + EXPECT_TRUE(file.Open(logfile)); + while ((bytesread = file.Read(buf, sizeof(buf) - 1)) > 0) + { + buf[bytesread] = '\0'; + logstring.append(buf); + } + file.Close(); + EXPECT_FALSE(logstring.empty()); + + EXPECT_STREQ("\xEF\xBB\xBF", logstring.substr(0, 3).c_str()); + + EXPECT_TRUE(regex.RegComp(".*(debug|DEBUG) <general>: regexp ovector=\\{\\[0,12\\],\\[0,4\\]," + "\\[5,11\\]\\}.*")); + EXPECT_GE(regex.RegFind(logstring), 0); + + EXPECT_TRUE(XFILE::CFile::Delete(logfile)); +} diff --git a/xbmc/utils/test/TestRingBuffer.cpp b/xbmc/utils/test/TestRingBuffer.cpp new file mode 100644 index 0000000..e2fd2d5 --- /dev/null +++ b/xbmc/utils/test/TestRingBuffer.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/RingBuffer.h" + +#include <gtest/gtest.h> + +TEST(TestRingBuffer, General) +{ + CRingBuffer a; + char data[20]; + unsigned int i; + + EXPECT_TRUE(a.Create(20)); + EXPECT_EQ((unsigned int)20, a.getSize()); + memset(data, 0, sizeof(data)); + for (i = 0; i < a.getSize(); i++) + EXPECT_TRUE(a.WriteData(data, 1)); + a.Clear(); + + memcpy(data, "0123456789", sizeof("0123456789")); + EXPECT_TRUE(a.WriteData(data, sizeof("0123456789"))); + EXPECT_STREQ("0123456789", a.getBuffer()); + + memset(data, 0, sizeof(data)); + EXPECT_TRUE(a.ReadData(data, 5)); + EXPECT_STREQ("01234", data); +} diff --git a/xbmc/utils/test/TestScraperParser.cpp b/xbmc/utils/test/TestScraperParser.cpp new file mode 100644 index 0000000..4ff4b06 --- /dev/null +++ b/xbmc/utils/test/TestScraperParser.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "test/TestUtils.h" +#include "utils/ScraperParser.h" + +#include <gtest/gtest.h> + +TEST(TestScraperParser, General) +{ + CScraperParser a; + + a.Clear(); + EXPECT_TRUE(a.Load(XBMC_REF_FILE_PATH("/addons/metadata.local/local.xml"))); + + EXPECT_STREQ(XBMC_REF_FILE_PATH("/addons/metadata.local/local.xml").c_str(), + a.GetFilename().c_str()); + EXPECT_STREQ("UTF-8", a.GetSearchStringEncoding().c_str()); +} diff --git a/xbmc/utils/test/TestScraperUrl.cpp b/xbmc/utils/test/TestScraperUrl.cpp new file mode 100644 index 0000000..1feb181 --- /dev/null +++ b/xbmc/utils/test/TestScraperUrl.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/ScraperUrl.h" + +#include <gtest/gtest.h> + +TEST(TestScraperUrl, General) +{ + CScraperUrl a; + std::string xmlstring; + + xmlstring = "<data spoof=\"blah\" gzip=\"yes\">\n" + " <someurl>\n" + " </someurl>\n" + " <someotherurl>\n" + " </someotherurl>\n" + "</data>\n"; + EXPECT_TRUE(a.ParseFromData(xmlstring)); + + const auto url = a.GetFirstUrlByType(); + EXPECT_STREQ("blah", url.m_spoof.c_str()); + EXPECT_STREQ("someurl", url.m_url.c_str()); + EXPECT_STREQ("", url.m_cache.c_str()); + EXPECT_EQ(CScraperUrl::UrlType::General, url.m_type); + EXPECT_FALSE(url.m_post); + EXPECT_TRUE(url.m_isgz); + EXPECT_EQ(-1, url.m_season); +} diff --git a/xbmc/utils/test/TestSortUtils.cpp b/xbmc/utils/test/TestSortUtils.cpp new file mode 100644 index 0000000..dac3c62 --- /dev/null +++ b/xbmc/utils/test/TestSortUtils.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/SortUtils.h" +#include "utils/Variant.h" + +#include <gtest/gtest.h> + +TEST(TestSortUtils, Sort_SortBy) +{ + SortItems items; + + CVariant variant1("M Artist"); + SortItemPtr item1(new SortItem()); + (*item1)[FieldArtist] = variant1; + CVariant variant2("B Artist"); + SortItemPtr item2(new SortItem()); + (*item2)[FieldArtist] = variant2; + CVariant variant3("R Artist"); + SortItemPtr item3(new SortItem()); + (*item3)[FieldArtist] = variant3; + CVariant variant4("R Artist"); + SortItemPtr item4(new SortItem()); + (*item4)[FieldArtist] = variant4; + CVariant variant5("I Artist"); + SortItemPtr item5(new SortItem()); + (*item5)[FieldArtist] = variant5; + CVariant variant6("A Artist"); + SortItemPtr item6(new SortItem()); + (*item6)[FieldArtist] = variant6; + CVariant variant7("G Artist"); + SortItemPtr item7(new SortItem()); + (*item7)[FieldArtist] = variant7; + + items.push_back(item1); + items.push_back(item2); + items.push_back(item3); + items.push_back(item4); + items.push_back(item5); + items.push_back(item6); + items.push_back(item7); + + SortUtils::Sort(SortByArtist, SortOrderAscending, SortAttributeNone, items); + + EXPECT_STREQ("A Artist", (*items.at(0))[FieldArtist].asString().c_str()); + EXPECT_STREQ("B Artist", (*items.at(1))[FieldArtist].asString().c_str()); + EXPECT_STREQ("G Artist", (*items.at(2))[FieldArtist].asString().c_str()); + EXPECT_STREQ("I Artist", (*items.at(3))[FieldArtist].asString().c_str()); + EXPECT_STREQ("M Artist", (*items.at(4))[FieldArtist].asString().c_str()); + EXPECT_STREQ("R Artist", (*items.at(5))[FieldArtist].asString().c_str()); + EXPECT_STREQ("R Artist", (*items.at(6))[FieldArtist].asString().c_str()); +} + +TEST(TestSortUtils, Sort_SortDescription) +{ + SortItems items; + + CVariant variant1("M Artist"); + SortItemPtr item1(new SortItem()); + (*item1)[FieldArtist] = variant1; + CVariant variant2("B Artist"); + SortItemPtr item2(new SortItem()); + (*item2)[FieldArtist] = variant2; + CVariant variant3("R Artist"); + SortItemPtr item3(new SortItem()); + (*item3)[FieldArtist] = variant3; + CVariant variant4("R Artist"); + SortItemPtr item4(new SortItem()); + (*item4)[FieldArtist] = variant4; + CVariant variant5("I Artist"); + SortItemPtr item5(new SortItem()); + (*item5)[FieldArtist] = variant5; + CVariant variant6("A Artist"); + SortItemPtr item6(new SortItem()); + (*item6)[FieldArtist] = variant6; + CVariant variant7("G Artist"); + SortItemPtr item7(new SortItem()); + (*item7)[FieldArtist] = variant7; + + items.push_back(item1); + items.push_back(item2); + items.push_back(item3); + items.push_back(item4); + items.push_back(item5); + items.push_back(item6); + items.push_back(item7); + + SortDescription desc; + desc.sortBy = SortByArtist; + SortUtils::Sort(desc, items); + + EXPECT_STREQ("A Artist", (*items.at(0))[FieldArtist].asString().c_str()); + EXPECT_STREQ("B Artist", (*items.at(1))[FieldArtist].asString().c_str()); + EXPECT_STREQ("G Artist", (*items.at(2))[FieldArtist].asString().c_str()); + EXPECT_STREQ("I Artist", (*items.at(3))[FieldArtist].asString().c_str()); + EXPECT_STREQ("M Artist", (*items.at(4))[FieldArtist].asString().c_str()); + EXPECT_STREQ("R Artist", (*items.at(5))[FieldArtist].asString().c_str()); + EXPECT_STREQ("R Artist", (*items.at(6))[FieldArtist].asString().c_str()); +} + +TEST(TestSortUtils, GetFieldsForSorting) +{ + Fields fields; + + fields = SortUtils::GetFieldsForSorting(SortByArtist); + Fields::iterator it; + it = fields.find(FieldAlbum); + EXPECT_EQ(FieldAlbum, *it); + it = fields.find(FieldArtist); + EXPECT_EQ(FieldArtist, *it); + it = fields.find(FieldArtistSort); + EXPECT_EQ(FieldArtistSort, *it); + it = fields.find(FieldYear); + EXPECT_EQ(FieldYear, *it); + it = fields.find(FieldTrackNumber); + EXPECT_EQ(FieldTrackNumber, *it); + EXPECT_EQ((unsigned int)5, fields.size()); +} diff --git a/xbmc/utils/test/TestStopwatch.cpp b/xbmc/utils/test/TestStopwatch.cpp new file mode 100644 index 0000000..82f555d --- /dev/null +++ b/xbmc/utils/test/TestStopwatch.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "threads/Thread.h" +#include "utils/Stopwatch.h" + +#include <gtest/gtest.h> + +using namespace std::chrono_literals; + +class CTestStopWatchThread : public CThread +{ +public: + CTestStopWatchThread() : + CThread("TestStopWatch"){} +}; + +TEST(TestStopWatch, Initialization) +{ + CStopWatch a; + EXPECT_FALSE(a.IsRunning()); + EXPECT_EQ(0.0f, a.GetElapsedSeconds()); + EXPECT_EQ(0.0f, a.GetElapsedMilliseconds()); +} + +TEST(TestStopWatch, Start) +{ + CStopWatch a; + a.Start(); + EXPECT_TRUE(a.IsRunning()); +} + +TEST(TestStopWatch, Stop) +{ + CStopWatch a; + a.Start(); + a.Stop(); + EXPECT_FALSE(a.IsRunning()); +} + +TEST(TestStopWatch, ElapsedTime) +{ + CStopWatch a; + CTestStopWatchThread thread; + a.Start(); + thread.Sleep(1ms); + EXPECT_GT(a.GetElapsedSeconds(), 0.0f); + EXPECT_GT(a.GetElapsedMilliseconds(), 0.0f); +} + +TEST(TestStopWatch, Reset) +{ + CStopWatch a; + CTestStopWatchThread thread; + a.StartZero(); + thread.Sleep(2ms); + EXPECT_GT(a.GetElapsedMilliseconds(), 1); + thread.Sleep(3ms); + a.Reset(); + EXPECT_LT(a.GetElapsedMilliseconds(), 5); +} diff --git a/xbmc/utils/test/TestStreamDetails.cpp b/xbmc/utils/test/TestStreamDetails.cpp new file mode 100644 index 0000000..7842eee --- /dev/null +++ b/xbmc/utils/test/TestStreamDetails.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/StreamDetails.h" + +#include <gtest/gtest.h> + +TEST(TestStreamDetails, General) +{ + CStreamDetails a; + CStreamDetailVideo *video = new CStreamDetailVideo(); + CStreamDetailAudio *audio = new CStreamDetailAudio(); + CStreamDetailSubtitle *subtitle = new CStreamDetailSubtitle(); + + video->m_iWidth = 1920; + video->m_iHeight = 1080; + video->m_fAspect = 2.39f; + video->m_iDuration = 30; + video->m_strCodec = "h264"; + video->m_strStereoMode = "left_right"; + video->m_strLanguage = "eng"; + + audio->m_iChannels = 2; + audio->m_strCodec = "aac"; + audio->m_strLanguage = "eng"; + + subtitle->m_strLanguage = "eng"; + + a.AddStream(video); + a.AddStream(audio); + + EXPECT_TRUE(a.HasItems()); + + EXPECT_EQ(1, a.GetStreamCount(CStreamDetail::VIDEO)); + EXPECT_EQ(1, a.GetVideoStreamCount()); + EXPECT_STREQ("", a.GetVideoCodec().c_str()); + EXPECT_EQ(0.0f, a.GetVideoAspect()); + EXPECT_EQ(0, a.GetVideoWidth()); + EXPECT_EQ(0, a.GetVideoHeight()); + EXPECT_EQ(0, a.GetVideoDuration()); + EXPECT_STREQ("", a.GetStereoMode().c_str()); + + EXPECT_EQ(1, a.GetStreamCount(CStreamDetail::AUDIO)); + EXPECT_EQ(1, a.GetAudioStreamCount()); + + EXPECT_EQ(0, a.GetStreamCount(CStreamDetail::SUBTITLE)); + EXPECT_EQ(0, a.GetSubtitleStreamCount()); + + a.AddStream(subtitle); + EXPECT_EQ(1, a.GetStreamCount(CStreamDetail::SUBTITLE)); + EXPECT_EQ(1, a.GetSubtitleStreamCount()); + + a.DetermineBestStreams(); + EXPECT_STREQ("h264", a.GetVideoCodec().c_str()); + EXPECT_EQ(2.39f, a.GetVideoAspect()); + EXPECT_EQ(1920, a.GetVideoWidth()); + EXPECT_EQ(1080, a.GetVideoHeight()); + EXPECT_EQ(30, a.GetVideoDuration()); + EXPECT_STREQ("left_right", a.GetStereoMode().c_str()); +} + +TEST(TestStreamDetails, VideoDimsToResolutionDescription) +{ + EXPECT_STREQ("1080", + CStreamDetails::VideoDimsToResolutionDescription(1920, 1080).c_str()); +} + +TEST(TestStreamDetails, VideoAspectToAspectDescription) +{ + EXPECT_STREQ("2.40", CStreamDetails::VideoAspectToAspectDescription(2.39f).c_str()); +} diff --git a/xbmc/utils/test/TestStreamUtils.cpp b/xbmc/utils/test/TestStreamUtils.cpp new file mode 100644 index 0000000..e23f958 --- /dev/null +++ b/xbmc/utils/test/TestStreamUtils.cpp @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/StreamUtils.h" + +#include <gtest/gtest.h> + +TEST(TestStreamUtils, General) +{ + EXPECT_EQ(0, StreamUtils::GetCodecPriority("")); + EXPECT_EQ(1, StreamUtils::GetCodecPriority("ac3")); + EXPECT_EQ(2, StreamUtils::GetCodecPriority("dca")); + EXPECT_EQ(3, StreamUtils::GetCodecPriority("eac3")); + EXPECT_EQ(4, StreamUtils::GetCodecPriority("dtshd_hra")); + EXPECT_EQ(5, StreamUtils::GetCodecPriority("dtshd_ma")); + EXPECT_EQ(6, StreamUtils::GetCodecPriority("truehd")); + EXPECT_EQ(7, StreamUtils::GetCodecPriority("flac")); +} diff --git a/xbmc/utils/test/TestStringUtils.cpp b/xbmc/utils/test/TestStringUtils.cpp new file mode 100644 index 0000000..82a78b1 --- /dev/null +++ b/xbmc/utils/test/TestStringUtils.cpp @@ -0,0 +1,609 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/StringUtils.h" + +#include <algorithm> + +#include <gtest/gtest.h> +enum class ECG +{ + A, + B +}; + +enum EG +{ + C, + D +}; + +namespace test_enum +{ +enum class ECN +{ + A = 1, + B +}; +enum EN +{ + C = 1, + D +}; +} +TEST(TestStringUtils, Format) +{ + std::string refstr = "test 25 2.7 ff FF"; + + std::string varstr = + StringUtils::Format("{} {} {:.1f} {:x} {:02X}", "test", 25, 2.743f, 0x00ff, 0x00ff); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + varstr = StringUtils::Format("", "test", 25, 2.743f, 0x00ff, 0x00ff); + EXPECT_STREQ("", varstr.c_str()); +} + +TEST(TestStringUtils, FormatEnum) +{ + const char* zero = "0"; + const char* one = "1"; + + std::string varstr = StringUtils::Format("{}", ECG::A); + EXPECT_STREQ(zero, varstr.c_str()); + + varstr = StringUtils::Format("{}", EG::C); + EXPECT_STREQ(zero, varstr.c_str()); + + varstr = StringUtils::Format("{}", test_enum::ECN::A); + EXPECT_STREQ(one, varstr.c_str()); + + varstr = StringUtils::Format("{}", test_enum::EN::C); + EXPECT_STREQ(one, varstr.c_str()); +} + +TEST(TestStringUtils, FormatEnumWidth) +{ + const char* one = "01"; + + std::string varstr = StringUtils::Format("{:02d}", ECG::B); + EXPECT_STREQ(one, varstr.c_str()); + + varstr = StringUtils::Format("{:02}", EG::D); + EXPECT_STREQ(one, varstr.c_str()); +} + +TEST(TestStringUtils, ToUpper) +{ + std::string refstr = "TEST"; + + std::string varstr = "TeSt"; + StringUtils::ToUpper(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, ToLower) +{ + std::string refstr = "test"; + + std::string varstr = "TeSt"; + StringUtils::ToLower(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, ToCapitalize) +{ + std::string refstr = "Test"; + std::string varstr = "test"; + StringUtils::ToCapitalize(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "Just A Test"; + varstr = "just a test"; + StringUtils::ToCapitalize(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "Test -1;2:3, String For Case"; + varstr = "test -1;2:3, string for Case"; + StringUtils::ToCapitalize(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = " JuST Another\t\tTEst:\nWoRKs "; + varstr = " juST another\t\ttEst:\nwoRKs "; + StringUtils::ToCapitalize(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "N.Y.P.D"; + varstr = "n.y.p.d"; + StringUtils::ToCapitalize(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "N-Y-P-D"; + varstr = "n-y-p-d"; + StringUtils::ToCapitalize(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, EqualsNoCase) +{ + std::string refstr = "TeSt"; + + EXPECT_TRUE(StringUtils::EqualsNoCase(refstr, "TeSt")); + EXPECT_TRUE(StringUtils::EqualsNoCase(refstr, "tEsT")); +} + +TEST(TestStringUtils, Left) +{ + std::string refstr, varstr; + std::string origstr = "test"; + + refstr = ""; + varstr = StringUtils::Left(origstr, 0); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "te"; + varstr = StringUtils::Left(origstr, 2); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "test"; + varstr = StringUtils::Left(origstr, 10); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, Mid) +{ + std::string refstr, varstr; + std::string origstr = "test"; + + refstr = ""; + varstr = StringUtils::Mid(origstr, 0, 0); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "te"; + varstr = StringUtils::Mid(origstr, 0, 2); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "test"; + varstr = StringUtils::Mid(origstr, 0, 10); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "st"; + varstr = StringUtils::Mid(origstr, 2); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "st"; + varstr = StringUtils::Mid(origstr, 2, 2); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "es"; + varstr = StringUtils::Mid(origstr, 1, 2); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, Right) +{ + std::string refstr, varstr; + std::string origstr = "test"; + + refstr = ""; + varstr = StringUtils::Right(origstr, 0); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "st"; + varstr = StringUtils::Right(origstr, 2); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + refstr = "test"; + varstr = StringUtils::Right(origstr, 10); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, Trim) +{ + std::string refstr = "test test"; + + std::string varstr = " test test "; + StringUtils::Trim(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, TrimLeft) +{ + std::string refstr = "test test "; + + std::string varstr = " test test "; + StringUtils::TrimLeft(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, TrimRight) +{ + std::string refstr = " test test"; + + std::string varstr = " test test "; + StringUtils::TrimRight(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, Replace) +{ + std::string refstr = "text text"; + + std::string varstr = "test test"; + EXPECT_EQ(StringUtils::Replace(varstr, 's', 'x'), 2); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + EXPECT_EQ(StringUtils::Replace(varstr, 's', 'x'), 0); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + varstr = "test test"; + EXPECT_EQ(StringUtils::Replace(varstr, "s", "x"), 2); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); + + EXPECT_EQ(StringUtils::Replace(varstr, "s", "x"), 0); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, StartsWith) +{ + std::string refstr = "test"; + + EXPECT_FALSE(StringUtils::StartsWithNoCase(refstr, "x")); + + EXPECT_TRUE(StringUtils::StartsWith(refstr, "te")); + EXPECT_TRUE(StringUtils::StartsWith(refstr, "test")); + EXPECT_FALSE(StringUtils::StartsWith(refstr, "Te")); + + EXPECT_TRUE(StringUtils::StartsWithNoCase(refstr, "Te")); + EXPECT_TRUE(StringUtils::StartsWithNoCase(refstr, "TesT")); +} + +TEST(TestStringUtils, EndsWith) +{ + std::string refstr = "test"; + + EXPECT_FALSE(StringUtils::EndsWithNoCase(refstr, "x")); + + EXPECT_TRUE(StringUtils::EndsWith(refstr, "st")); + EXPECT_TRUE(StringUtils::EndsWith(refstr, "test")); + EXPECT_FALSE(StringUtils::EndsWith(refstr, "sT")); + + EXPECT_TRUE(StringUtils::EndsWithNoCase(refstr, "sT")); + EXPECT_TRUE(StringUtils::EndsWithNoCase(refstr, "TesT")); +} + +TEST(TestStringUtils, Join) +{ + std::string refstr, varstr; + std::vector<std::string> strarray; + + strarray.emplace_back("a"); + strarray.emplace_back("b"); + strarray.emplace_back("c"); + strarray.emplace_back("de"); + strarray.emplace_back(","); + strarray.emplace_back("fg"); + strarray.emplace_back(","); + refstr = "a,b,c,de,,,fg,,"; + varstr = StringUtils::Join(strarray, ","); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, Split) +{ + std::vector<std::string> varresults; + + // test overload with string as delimiter + varresults = StringUtils::Split("g,h,ij,k,lm,,n", ","); + EXPECT_STREQ("g", varresults.at(0).c_str()); + EXPECT_STREQ("h", varresults.at(1).c_str()); + EXPECT_STREQ("ij", varresults.at(2).c_str()); + EXPECT_STREQ("k", varresults.at(3).c_str()); + EXPECT_STREQ("lm", varresults.at(4).c_str()); + EXPECT_STREQ("", varresults.at(5).c_str()); + EXPECT_STREQ("n", varresults.at(6).c_str()); + + EXPECT_TRUE(StringUtils::Split("", "|").empty()); + + EXPECT_EQ(4U, StringUtils::Split("a bc d ef ghi ", " ", 4).size()); + EXPECT_STREQ("d ef ghi ", StringUtils::Split("a bc d ef ghi ", " ", 4).at(3).c_str()) << "Last part must include rest of the input string"; + EXPECT_EQ(7U, StringUtils::Split("a bc d ef ghi ", " ").size()) << "Result must be 7 strings including two empty strings"; + EXPECT_STREQ("bc", StringUtils::Split("a bc d ef ghi ", " ").at(1).c_str()); + EXPECT_STREQ("", StringUtils::Split("a bc d ef ghi ", " ").at(2).c_str()); + EXPECT_STREQ("", StringUtils::Split("a bc d ef ghi ", " ").at(6).c_str()); + + EXPECT_EQ(2U, StringUtils::Split("a bc d ef ghi ", " ").size()); + EXPECT_EQ(2U, StringUtils::Split("a bc d ef ghi ", " ", 10).size()); + EXPECT_STREQ("a bc", StringUtils::Split("a bc d ef ghi ", " ", 10).at(0).c_str()); + + EXPECT_EQ(1U, StringUtils::Split("a bc d ef ghi ", " z").size()); + EXPECT_STREQ("a bc d ef ghi ", StringUtils::Split("a bc d ef ghi ", " z").at(0).c_str()); + + EXPECT_EQ(1U, StringUtils::Split("a bc d ef ghi ", "").size()); + EXPECT_STREQ("a bc d ef ghi ", StringUtils::Split("a bc d ef ghi ", "").at(0).c_str()); + + // test overload with char as delimiter + EXPECT_EQ(4U, StringUtils::Split("a bc d ef ghi ", ' ', 4).size()); + EXPECT_STREQ("d ef ghi ", StringUtils::Split("a bc d ef ghi ", ' ', 4).at(3).c_str()); + EXPECT_EQ(7U, StringUtils::Split("a bc d ef ghi ", ' ').size()) << "Result must be 7 strings including two empty strings"; + EXPECT_STREQ("bc", StringUtils::Split("a bc d ef ghi ", ' ').at(1).c_str()); + EXPECT_STREQ("", StringUtils::Split("a bc d ef ghi ", ' ').at(2).c_str()); + EXPECT_STREQ("", StringUtils::Split("a bc d ef ghi ", ' ').at(6).c_str()); + + EXPECT_EQ(1U, StringUtils::Split("a bc d ef ghi ", 'z').size()); + EXPECT_STREQ("a bc d ef ghi ", StringUtils::Split("a bc d ef ghi ", 'z').at(0).c_str()); + + EXPECT_EQ(1U, StringUtils::Split("a bc d ef ghi ", "").size()); + EXPECT_STREQ("a bc d ef ghi ", StringUtils::Split("a bc d ef ghi ", 'z').at(0).c_str()); +} + +TEST(TestStringUtils, FindNumber) +{ + EXPECT_EQ(3, StringUtils::FindNumber("aabcaadeaa", "aa")); + EXPECT_EQ(1, StringUtils::FindNumber("aabcaadeaa", "b")); +} + +TEST(TestStringUtils, AlphaNumericCompare) +{ + int64_t ref, var; + + ref = 0; + var = StringUtils::AlphaNumericCompare(L"123abc", L"abc123"); + EXPECT_LT(var, ref); +} + +TEST(TestStringUtils, TimeStringToSeconds) +{ + EXPECT_EQ(77455, StringUtils::TimeStringToSeconds("21:30:55")); + EXPECT_EQ(7*60, StringUtils::TimeStringToSeconds("7 min")); + EXPECT_EQ(7*60, StringUtils::TimeStringToSeconds("7 min\t")); + EXPECT_EQ(154*60, StringUtils::TimeStringToSeconds(" 154 min")); + EXPECT_EQ(1*60+1, StringUtils::TimeStringToSeconds("1:01")); + EXPECT_EQ(4*60+3, StringUtils::TimeStringToSeconds("4:03")); + EXPECT_EQ(2*3600+4*60+3, StringUtils::TimeStringToSeconds("2:04:03")); + EXPECT_EQ(2*3600+4*60+3, StringUtils::TimeStringToSeconds(" 2:4:3")); + EXPECT_EQ(2*3600+4*60+3, StringUtils::TimeStringToSeconds(" \t\t 02:04:03 \n ")); + EXPECT_EQ(1*3600+5*60+2, StringUtils::TimeStringToSeconds("01:05:02:04:03 \n ")); + EXPECT_EQ(0, StringUtils::TimeStringToSeconds("blah")); + EXPECT_EQ(0, StringUtils::TimeStringToSeconds("ля-ля")); +} + +TEST(TestStringUtils, RemoveCRLF) +{ + std::string refstr, varstr; + + refstr = "test\r\nstring\nblah blah"; + varstr = "test\r\nstring\nblah blah\n"; + StringUtils::RemoveCRLF(varstr); + EXPECT_STREQ(refstr.c_str(), varstr.c_str()); +} + +TEST(TestStringUtils, utf8_strlen) +{ + size_t ref, var; + + ref = 9; + var = StringUtils::utf8_strlen("test_UTF8"); + EXPECT_EQ(ref, var); +} + +TEST(TestStringUtils, SecondsToTimeString) +{ + std::string ref, var; + + ref = "21:30:55"; + var = StringUtils::SecondsToTimeString(77455); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST(TestStringUtils, IsNaturalNumber) +{ + EXPECT_TRUE(StringUtils::IsNaturalNumber("10")); + EXPECT_TRUE(StringUtils::IsNaturalNumber(" 10")); + EXPECT_TRUE(StringUtils::IsNaturalNumber("0")); + EXPECT_FALSE(StringUtils::IsNaturalNumber(" 1 0")); + EXPECT_FALSE(StringUtils::IsNaturalNumber("1.0")); + EXPECT_FALSE(StringUtils::IsNaturalNumber("1.1")); + EXPECT_FALSE(StringUtils::IsNaturalNumber("0x1")); + EXPECT_FALSE(StringUtils::IsNaturalNumber("blah")); + EXPECT_FALSE(StringUtils::IsNaturalNumber("120 h")); + EXPECT_FALSE(StringUtils::IsNaturalNumber(" ")); + EXPECT_FALSE(StringUtils::IsNaturalNumber("")); +} + +TEST(TestStringUtils, IsInteger) +{ + EXPECT_TRUE(StringUtils::IsInteger("10")); + EXPECT_TRUE(StringUtils::IsInteger(" -10")); + EXPECT_TRUE(StringUtils::IsInteger("0")); + EXPECT_FALSE(StringUtils::IsInteger(" 1 0")); + EXPECT_FALSE(StringUtils::IsInteger("1.0")); + EXPECT_FALSE(StringUtils::IsInteger("1.1")); + EXPECT_FALSE(StringUtils::IsInteger("0x1")); + EXPECT_FALSE(StringUtils::IsInteger("blah")); + EXPECT_FALSE(StringUtils::IsInteger("120 h")); + EXPECT_FALSE(StringUtils::IsInteger(" ")); + EXPECT_FALSE(StringUtils::IsInteger("")); +} + +TEST(TestStringUtils, SizeToString) +{ + std::string ref, var; + + ref = "2.00 GB"; + var = StringUtils::SizeToString(2147483647); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "0.00 B"; + var = StringUtils::SizeToString(0); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST(TestStringUtils, EmptyString) +{ + EXPECT_STREQ("", StringUtils::Empty.c_str()); +} + +TEST(TestStringUtils, FindWords) +{ + size_t ref, var; + + ref = 5; + var = StringUtils::FindWords("test string", "string"); + EXPECT_EQ(ref, var); + var = StringUtils::FindWords("12345string", "string"); + EXPECT_EQ(ref, var); + var = StringUtils::FindWords("apple2012", "2012"); + EXPECT_EQ(ref, var); + ref = -1; + var = StringUtils::FindWords("12345string", "ring"); + EXPECT_EQ(ref, var); + var = StringUtils::FindWords("12345string", "345"); + EXPECT_EQ(ref, var); + var = StringUtils::FindWords("apple2012", "e2012"); + EXPECT_EQ(ref, var); + var = StringUtils::FindWords("apple2012", "12"); + EXPECT_EQ(ref, var); +} + +TEST(TestStringUtils, FindWords_NonAscii) +{ + size_t ref, var; + + ref = 6; + var = StringUtils::FindWords("我的视频", "视频"); + EXPECT_EQ(ref, var); + var = StringUtils::FindWords("我的视频", "视"); + EXPECT_EQ(ref, var); + var = StringUtils::FindWords("Apple ple", "ple"); + EXPECT_EQ(ref, var); + ref = 7; + var = StringUtils::FindWords("Äpfel.pfel", "pfel"); + EXPECT_EQ(ref, var); +} + +TEST(TestStringUtils, FindEndBracket) +{ + int ref, var; + + ref = 11; + var = StringUtils::FindEndBracket("atest testbb test", 'a', 'b'); + EXPECT_EQ(ref, var); +} + +TEST(TestStringUtils, DateStringToYYYYMMDD) +{ + int ref, var; + + ref = 20120706; + var = StringUtils::DateStringToYYYYMMDD("2012-07-06"); + EXPECT_EQ(ref, var); +} + +TEST(TestStringUtils, WordToDigits) +{ + std::string ref, var; + + ref = "8378 787464"; + var = "test string"; + StringUtils::WordToDigits(var); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST(TestStringUtils, CreateUUID) +{ + std::cout << "CreateUUID(): " << StringUtils::CreateUUID() << std::endl; +} + +TEST(TestStringUtils, ValidateUUID) +{ + EXPECT_TRUE(StringUtils::ValidateUUID(StringUtils::CreateUUID())); +} + +TEST(TestStringUtils, CompareFuzzy) +{ + double ref, var; + + ref = 6.25; + var = StringUtils::CompareFuzzy("test string", "string test"); + EXPECT_EQ(ref, var); +} + +TEST(TestStringUtils, FindBestMatch) +{ + double refdouble, vardouble; + int refint, varint; + std::vector<std::string> strarray; + + refint = 3; + refdouble = 0.5625; + strarray.emplace_back(""); + strarray.emplace_back("a"); + strarray.emplace_back("e"); + strarray.emplace_back("es"); + strarray.emplace_back("t"); + varint = StringUtils::FindBestMatch("test", strarray, vardouble); + EXPECT_EQ(refint, varint); + EXPECT_EQ(refdouble, vardouble); +} + +TEST(TestStringUtils, Paramify) +{ + const char *input = "some, very \\ odd \"string\""; + const char *ref = "\"some, very \\\\ odd \\\"string\\\"\""; + + std::string result = StringUtils::Paramify(input); + EXPECT_STREQ(ref, result.c_str()); +} + +TEST(TestStringUtils, sortstringbyname) +{ + std::vector<std::string> strarray; + strarray.emplace_back("B"); + strarray.emplace_back("c"); + strarray.emplace_back("a"); + std::sort(strarray.begin(), strarray.end(), sortstringbyname()); + + EXPECT_STREQ("a", strarray[0].c_str()); + EXPECT_STREQ("B", strarray[1].c_str()); + EXPECT_STREQ("c", strarray[2].c_str()); +} + +TEST(TestStringUtils, FileSizeFormat) +{ + EXPECT_STREQ("0B", StringUtils::FormatFileSize(0).c_str()); + + EXPECT_STREQ("999B", StringUtils::FormatFileSize(999).c_str()); + EXPECT_STREQ("0.98kB", StringUtils::FormatFileSize(1000).c_str()); + + EXPECT_STREQ("1.00kB", StringUtils::FormatFileSize(1024).c_str()); + EXPECT_STREQ("9.99kB", StringUtils::FormatFileSize(10229).c_str()); + + EXPECT_STREQ("10.1kB", StringUtils::FormatFileSize(10387).c_str()); + EXPECT_STREQ("99.9kB", StringUtils::FormatFileSize(102297).c_str()); + + EXPECT_STREQ("100kB", StringUtils::FormatFileSize(102400).c_str()); + EXPECT_STREQ("999kB", StringUtils::FormatFileSize(1023431).c_str()); + + EXPECT_STREQ("0.98MB", StringUtils::FormatFileSize(1023897).c_str()); + EXPECT_STREQ("0.98MB", StringUtils::FormatFileSize(1024000).c_str()); + + //Last unit should overflow the 3 digit limit + EXPECT_STREQ("5432PB", StringUtils::FormatFileSize(6115888293969133568).c_str()); +} + +TEST(TestStringUtils, ToHexadecimal) +{ + EXPECT_STREQ("", StringUtils::ToHexadecimal("").c_str()); + EXPECT_STREQ("616263", StringUtils::ToHexadecimal("abc").c_str()); + std::string a{"a\0b\n", 4}; + EXPECT_STREQ("6100620a", StringUtils::ToHexadecimal(a).c_str()); + std::string nul{"\0", 1}; + EXPECT_STREQ("00", StringUtils::ToHexadecimal(nul).c_str()); + std::string ff{"\xFF", 1}; + EXPECT_STREQ("ff", StringUtils::ToHexadecimal(ff).c_str()); +} diff --git a/xbmc/utils/test/TestSystemInfo.cpp b/xbmc/utils/test/TestSystemInfo.cpp new file mode 100644 index 0000000..d14a474 --- /dev/null +++ b/xbmc/utils/test/TestSystemInfo.cpp @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "GUIInfoManager.h" +#include "ServiceBroker.h" +#include "settings/Settings.h" +#include "utils/CPUInfo.h" +#include "utils/SystemInfo.h" +#if defined(TARGET_WINDOWS) +#include "platform/win32/CharsetConverter.h" +#endif + +#include <gtest/gtest.h> + +#include "PlatformDefs.h" + +class TestSystemInfo : public testing::Test +{ +protected: + TestSystemInfo() { CServiceBroker::RegisterCPUInfo(CCPUInfo::GetCPUInfo()); } + ~TestSystemInfo() { CServiceBroker::UnregisterCPUInfo(); } +}; + +TEST_F(TestSystemInfo, Print_System_Info) +{ + std::cout << "'GetKernelName(false)': \"" << g_sysinfo.GetKernelName(true) << "\"\n"; + std::cout << "'GetKernelVersion()': \"" << g_sysinfo.GetKernelVersion() << "\"\n"; + std::cout << "'GetKernelVersionFull()': \"" << g_sysinfo.GetKernelVersionFull() << "\"\n"; + std::cout << "'GetOsPrettyNameWithVersion()': \"" << g_sysinfo.GetOsPrettyNameWithVersion() << "\"\n"; + std::cout << "'GetOsName(false)': \"" << g_sysinfo.GetOsName(false) << "\"\n"; + std::cout << "'GetOsVersion()': \"" << g_sysinfo.GetOsVersion() << "\"\n"; + std::cout << "'GetKernelCpuFamily()': \"" << g_sysinfo.GetKernelCpuFamily() << "\"\n"; + std::cout << "'GetKernelBitness()': \"" << g_sysinfo.GetKernelBitness() << "\"\n"; + std::cout << "'GetBuildTargetPlatformName()': \"" << g_sysinfo.GetBuildTargetPlatformName() << "\"\n"; + std::cout << "'GetBuildTargetPlatformVersionDecoded()': \"" << g_sysinfo.GetBuildTargetPlatformVersionDecoded() << "\"\n"; + std::cout << "'GetBuildTargetPlatformVersion()': \"" << g_sysinfo.GetBuildTargetPlatformVersion() << "\"\n"; + std::cout << "'GetBuildTargetCpuFamily()': \"" << g_sysinfo.GetBuildTargetCpuFamily() << "\"\n"; + std::cout << "'GetXbmcBitness()': \"" << g_sysinfo.GetXbmcBitness() << "\"\n"; + std::cout << "'GetUsedCompilerNameAndVer()': \"" << g_sysinfo.GetUsedCompilerNameAndVer() << "\"\n"; + std::cout << "'GetManufacturerName()': \"" << g_sysinfo.GetManufacturerName() << "\"\n"; + std::cout << "'GetModelName()': \"" << g_sysinfo.GetModelName() << "\"\n"; + std::cout << "'GetUserAgent()': \"" << g_sysinfo.GetUserAgent() << "\"\n"; +} + +TEST_F(TestSystemInfo, GetKernelName) +{ + EXPECT_FALSE(g_sysinfo.GetKernelName(true).empty()) << "'GetKernelName(true)' must not return empty kernel name"; + EXPECT_FALSE(g_sysinfo.GetKernelName(false).empty()) << "'GetKernelName(false)' must not return empty kernel name"; + EXPECT_STRCASENE("Unknown kernel", g_sysinfo.GetKernelName(true).c_str()) << "'GetKernelName(true)' must not return 'Unknown kernel'"; + EXPECT_STRCASENE("Unknown kernel", g_sysinfo.GetKernelName(false).c_str()) << "'GetKernelName(false)' must not return 'Unknown kernel'"; +#ifndef TARGET_DARWIN + EXPECT_EQ(g_sysinfo.GetBuildTargetPlatformName(), g_sysinfo.GetKernelName(true)) << "'GetKernelName(true)' must match GetBuildTargetPlatformName()"; + EXPECT_EQ(g_sysinfo.GetBuildTargetPlatformName(), g_sysinfo.GetKernelName(false)) << "'GetKernelName(false)' must match GetBuildTargetPlatformName()"; +#endif // !TARGET_DARWIN +#if defined(TARGET_WINDOWS) + EXPECT_NE(std::string::npos, g_sysinfo.GetKernelName(true).find("Windows")) << "'GetKernelName(true)' must contain 'Windows'"; + EXPECT_NE(std::string::npos, g_sysinfo.GetKernelName(false).find("Windows")) << "'GetKernelName(false)' must contain 'Windows'"; +#elif defined(TARGET_FREEBSD) + EXPECT_STREQ("FreeBSD", g_sysinfo.GetKernelName(true).c_str()) << "'GetKernelName(true)' must return 'FreeBSD'"; + EXPECT_STREQ("FreeBSD", g_sysinfo.GetKernelName(false).c_str()) << "'GetKernelName(false)' must return 'FreeBSD'"; +#elif defined(TARGET_DARWIN) + EXPECT_STREQ("Darwin", g_sysinfo.GetKernelName(true).c_str()) << "'GetKernelName(true)' must return 'Darwin'"; + EXPECT_STREQ("Darwin", g_sysinfo.GetKernelName(false).c_str()) << "'GetKernelName(false)' must return 'Darwin'"; +#elif defined(TARGET_LINUX) + EXPECT_STREQ("Linux", g_sysinfo.GetKernelName(true).c_str()) << "'GetKernelName(true)' must return 'Linux'"; + EXPECT_STREQ("Linux", g_sysinfo.GetKernelName(false).c_str()) << "'GetKernelName(false)' must return 'Linux'"; +#endif +} + +TEST_F(TestSystemInfo, GetKernelVersionFull) +{ + EXPECT_FALSE(g_sysinfo.GetKernelVersionFull().empty()) << "'GetKernelVersionFull()' must not return empty string"; + EXPECT_STRNE("0.0.0", g_sysinfo.GetKernelVersionFull().c_str()) << "'GetKernelVersionFull()' must not return '0.0.0'"; + EXPECT_STRNE("0.0", g_sysinfo.GetKernelVersionFull().c_str()) << "'GetKernelVersionFull()' must not return '0.0'"; + EXPECT_EQ(0U, g_sysinfo.GetKernelVersionFull().find_first_of("0123456789")) << "'GetKernelVersionFull()' must not return version not starting from digit"; +} + +TEST_F(TestSystemInfo, GetKernelVersion) +{ + EXPECT_FALSE(g_sysinfo.GetKernelVersion().empty()) << "'GetKernelVersion()' must not return empty string"; + EXPECT_STRNE("0.0.0", g_sysinfo.GetKernelVersion().c_str()) << "'GetKernelVersion()' must not return '0.0.0'"; + EXPECT_STRNE("0.0", g_sysinfo.GetKernelVersion().c_str()) << "'GetKernelVersion()' must not return '0.0'"; + EXPECT_EQ(0U, g_sysinfo.GetKernelVersion().find_first_of("0123456789")) << "'GetKernelVersion()' must not return version not starting from digit"; + EXPECT_EQ(std::string::npos, g_sysinfo.GetKernelVersion().find_first_not_of("0123456789.")) << "'GetKernelVersion()' must not return version with not only digits and dots"; +} + +TEST_F(TestSystemInfo, GetOsName) +{ + EXPECT_FALSE(g_sysinfo.GetOsName(true).empty()) << "'GetOsName(true)' must not return empty OS name"; + EXPECT_FALSE(g_sysinfo.GetOsName(false).empty()) << "'GetOsName(false)' must not return empty OS name"; + EXPECT_STRCASENE("Unknown OS", g_sysinfo.GetOsName(true).c_str()) << "'GetOsName(true)' must not return 'Unknown OS'"; + EXPECT_STRCASENE("Unknown OS", g_sysinfo.GetOsName(false).c_str()) << "'GetOsName(false)' must not return 'Unknown OS'"; +#if defined(TARGET_WINDOWS) + EXPECT_NE(std::string::npos, g_sysinfo.GetOsName(true).find("Windows")) << "'GetOsName(true)' must contain 'Windows'"; + EXPECT_NE(std::string::npos, g_sysinfo.GetOsName(false).find("Windows")) << "'GetOsName(false)' must contain 'Windows'"; +#elif defined(TARGET_FREEBSD) + EXPECT_STREQ("FreeBSD", g_sysinfo.GetOsName(true).c_str()) << "'GetOsName(true)' must return 'FreeBSD'"; + EXPECT_STREQ("FreeBSD", g_sysinfo.GetOsName(false).c_str()) << "'GetOsName(false)' must return 'FreeBSD'"; +#elif defined(TARGET_DARWIN_IOS) + EXPECT_STREQ("iOS", g_sysinfo.GetOsName(true).c_str()) << "'GetOsName(true)' must return 'iOS'"; + EXPECT_STREQ("iOS", g_sysinfo.GetOsName(false).c_str()) << "'GetOsName(false)' must return 'iOS'"; +#elif defined(TARGET_DARWIN_TVOS) + EXPECT_STREQ("tvOS", g_sysinfo.GetOsName(true).c_str()) << "'GetOsName(true)' must return 'tvOS'"; + EXPECT_STREQ("tvOS", g_sysinfo.GetOsName(false).c_str()) + << "'GetOsName(false)' must return 'tvOS'"; +#elif defined(TARGET_DARWIN_OSX) + EXPECT_STREQ("macOS", g_sysinfo.GetOsName(true).c_str()) + << "'GetOsName(true)' must return 'macOS'"; + EXPECT_STREQ("macOS", g_sysinfo.GetOsName(false).c_str()) + << "'GetOsName(false)' must return 'macOS'"; +#elif defined(TARGET_ANDROID) + EXPECT_STREQ("Android", g_sysinfo.GetOsName(true).c_str()) << "'GetOsName(true)' must return 'Android'"; + EXPECT_STREQ("Android", g_sysinfo.GetOsName(false).c_str()) << "'GetOsName(false)' must return 'Android'"; +#endif +#ifdef TARGET_DARWIN + EXPECT_EQ(g_sysinfo.GetBuildTargetPlatformName(), g_sysinfo.GetOsName(true)) << "'GetOsName(true)' must match GetBuildTargetPlatformName()"; + EXPECT_EQ(g_sysinfo.GetBuildTargetPlatformName(), g_sysinfo.GetOsName(false)) << "'GetOsName(false)' must match GetBuildTargetPlatformName()"; +#endif // TARGET_DARWIN +} + +TEST_F(TestSystemInfo, DISABLED_GetOsVersion) +{ + EXPECT_FALSE(g_sysinfo.GetOsVersion().empty()) << "'GetOsVersion()' must not return empty string"; + EXPECT_STRNE("0.0.0", g_sysinfo.GetOsVersion().c_str()) << "'GetOsVersion()' must not return '0.0.0'"; + EXPECT_STRNE("0.0", g_sysinfo.GetOsVersion().c_str()) << "'GetOsVersion()' must not return '0.0'"; + EXPECT_EQ(0U, g_sysinfo.GetOsVersion().find_first_of("0123456789")) << "'GetOsVersion()' must not return version not starting from digit"; + EXPECT_EQ(std::string::npos, g_sysinfo.GetOsVersion().find_first_not_of("0123456789.")) << "'GetOsVersion()' must not return version with not only digits and dots"; +} + +TEST_F(TestSystemInfo, GetOsPrettyNameWithVersion) +{ + EXPECT_FALSE(g_sysinfo.GetOsPrettyNameWithVersion().empty()) << "'GetOsPrettyNameWithVersion()' must not return empty string"; + EXPECT_EQ(std::string::npos, g_sysinfo.GetOsPrettyNameWithVersion().find("Unknown")) << "'GetOsPrettyNameWithVersion()' must not contain 'Unknown'"; + EXPECT_EQ(std::string::npos, g_sysinfo.GetOsPrettyNameWithVersion().find("unknown")) << "'GetOsPrettyNameWithVersion()' must not contain 'unknown'"; +#ifdef TARGET_WINDOWS + EXPECT_NE(std::string::npos, g_sysinfo.GetOsPrettyNameWithVersion().find("Windows")) << "'GetOsPrettyNameWithVersion()' must contain 'Windows'"; +#else // ! TARGET_WINDOWS + EXPECT_NE(std::string::npos, g_sysinfo.GetOsPrettyNameWithVersion().find(g_sysinfo.GetOsVersion())) << "'GetOsPrettyNameWithVersion()' must contain OS version"; +#endif // ! TARGET_WINDOWS +} + +TEST_F(TestSystemInfo, GetManufacturerName) +{ + EXPECT_STRCASENE("unknown", g_sysinfo.GetManufacturerName().c_str()) << "'GetManufacturerName()' must return empty string instead of 'Unknown'"; +} + +TEST_F(TestSystemInfo, GetModelName) +{ + EXPECT_STRCASENE("unknown", g_sysinfo.GetModelName().c_str()) << "'GetModelName()' must return empty string instead of 'Unknown'"; +} + +#ifndef TARGET_WINDOWS +TEST_F(TestSystemInfo, IsAeroDisabled) +{ + EXPECT_FALSE(g_sysinfo.IsAeroDisabled()) << "'IsAeroDisabled()' must return 'false'"; +} +#endif // ! TARGET_WINDOWS + +TEST_F(TestSystemInfo, IsWindowsVersion) +{ + EXPECT_FALSE(g_sysinfo.IsWindowsVersion(CSysInfo::WindowsVersionUnknown)) << "'IsWindowsVersion()' must return 'false' for 'WindowsVersionUnknown'"; +#ifndef TARGET_WINDOWS + EXPECT_FALSE(g_sysinfo.IsWindowsVersion(CSysInfo::WindowsVersionWin7)) << "'IsWindowsVersion()' must return 'false'"; +#endif // ! TARGET_WINDOWS +} + +TEST_F(TestSystemInfo, IsWindowsVersionAtLeast) +{ + EXPECT_FALSE(g_sysinfo.IsWindowsVersionAtLeast(CSysInfo::WindowsVersionUnknown)) << "'IsWindowsVersionAtLeast()' must return 'false' for 'WindowsVersionUnknown'"; + EXPECT_FALSE(g_sysinfo.IsWindowsVersionAtLeast(CSysInfo::WindowsVersionFuture)) << "'IsWindowsVersionAtLeast()' must return 'false' for 'WindowsVersionFuture'"; +#ifndef TARGET_WINDOWS + EXPECT_FALSE(g_sysinfo.IsWindowsVersion(CSysInfo::WindowsVersionWin7)) << "'IsWindowsVersionAtLeast()' must return 'false'"; +#endif // ! TARGET_WINDOWS +} + +TEST_F(TestSystemInfo, GetWindowsVersion) +{ +#ifdef TARGET_WINDOWS + EXPECT_NE(CSysInfo::WindowsVersionUnknown, g_sysinfo.GetWindowsVersion()) << "'GetWindowsVersion()' must not return 'WindowsVersionUnknown'"; + EXPECT_NE(CSysInfo::WindowsVersionFuture, g_sysinfo.GetWindowsVersion()) << "'GetWindowsVersion()' must not return 'WindowsVersionFuture'"; +#else // ! TARGET_WINDOWS + EXPECT_EQ(CSysInfo::WindowsVersionUnknown, g_sysinfo.GetWindowsVersion()) << "'GetWindowsVersion()' must return 'WindowsVersionUnknown'"; +#endif // ! TARGET_WINDOWS +} + +TEST_F(TestSystemInfo, GetKernelBitness) +{ + EXPECT_TRUE(g_sysinfo.GetKernelBitness() == 32 || g_sysinfo.GetKernelBitness() == 64) << "'GetKernelBitness()' must return '32' or '64', but not '" << g_sysinfo.GetKernelBitness() << "'"; + EXPECT_LE(g_sysinfo.GetXbmcBitness(), g_sysinfo.GetKernelBitness()) << "'GetKernelBitness()' must be greater or equal to 'GetXbmcBitness()'"; +} + +TEST_F(TestSystemInfo, GetKernelCpuFamily) +{ + EXPECT_STRNE("unknown CPU family", g_sysinfo.GetKernelCpuFamily().c_str()) << "'GetKernelCpuFamily()' must not return 'unknown CPU family'"; +#if defined(__thumb__) || defined(_M_ARMT) || defined(__arm__) || defined(_M_ARM) || defined (__aarch64__) + EXPECT_STREQ("ARM", g_sysinfo.GetKernelCpuFamily().c_str()) << "'GetKernelCpuFamily()' must return 'ARM'"; +#else // ! ARM + EXPECT_EQ(g_sysinfo.GetBuildTargetCpuFamily(), g_sysinfo.GetKernelCpuFamily()) << "'GetKernelCpuFamily()' must match 'GetBuildTargetCpuFamily()'"; +#endif // ! ARM +} + +TEST_F(TestSystemInfo, GetXbmcBitness) +{ + EXPECT_TRUE(g_sysinfo.GetXbmcBitness() == 32 || g_sysinfo.GetXbmcBitness() == 64) << "'GetXbmcBitness()' must return '32' or '64', but not '" << g_sysinfo.GetXbmcBitness() << "'"; + EXPECT_GE(g_sysinfo.GetKernelBitness(), g_sysinfo.GetXbmcBitness()) << "'GetXbmcBitness()' must be not greater than 'GetKernelBitness()'"; +} + +TEST_F(TestSystemInfo, GetUserAgent) +{ + EXPECT_STREQ(g_sysinfo.GetAppName().c_str(), g_sysinfo.GetUserAgent().substr(0, g_sysinfo.GetAppName().size()).c_str()) << "'GetUserAgent()' string must start with app name'"; + EXPECT_NE(std::string::npos, g_sysinfo.GetUserAgent().find('(')) << "'GetUserAgent()' must contain brackets around second parameter"; + EXPECT_NE(std::string::npos, g_sysinfo.GetUserAgent().find(')')) << "'GetUserAgent()' must contain brackets around second parameter"; + EXPECT_EQ(g_sysinfo.GetUserAgent().find(' '), g_sysinfo.GetUserAgent().find(" (")) << "Second parameter in 'GetUserAgent()' string must be in brackets"; + EXPECT_EQ(g_sysinfo.GetUserAgent().find(" (") + 1, g_sysinfo.GetUserAgent().find('(')) << "'GetUserAgent()' string must not contain any opening brackets before second parameter"; + EXPECT_GT(g_sysinfo.GetUserAgent().find(')'), g_sysinfo.GetUserAgent().find('(')) << "'GetUserAgent()' string must not contain any closing brackets before second parameter"; + EXPECT_EQ(g_sysinfo.GetUserAgent().find(") "), g_sysinfo.GetUserAgent().find(')')) << "'GetUserAgent()' string must not contain any closing brackets before end of second parameter"; +#if defined(TARGET_WINDOWS) + EXPECT_EQ(g_sysinfo.GetUserAgent().find('('), g_sysinfo.GetUserAgent().find("(Windows")) << "Second parameter in 'GetUserAgent()' string must start from `Windows`"; + EXPECT_NE(std::string::npos, g_sysinfo.GetUserAgent().find("Windows")) << "'GetUserAgent()' must contain 'Windows'"; +#elif defined(TARGET_DARWIN_IOS) + EXPECT_NE(std::string::npos, g_sysinfo.GetUserAgent().find("like Mac OS X")) << "'GetUserAgent()' must contain ' like Mac OS X'"; + EXPECT_TRUE(g_sysinfo.GetUserAgent().find("CPU OS ") != std::string::npos || g_sysinfo.GetUserAgent().find("CPU iPhone OS ") != std::string::npos) << "'GetUserAgent()' must contain 'CPU OS ' or 'CPU iPhone OS '"; +#elif defined(TARGET_DARWIN_TVOS) + EXPECT_NE(std::string::npos, g_sysinfo.GetUserAgent().find("like Mac OS X")) + << "'GetUserAgent()' must contain ' like Mac OS X'"; + EXPECT_TRUE(g_sysinfo.GetUserAgent().find("CPU TVOS ") != std::string::npos) + << "'GetUserAgent()' must contain 'CPU TVOS '"; +#elif defined(TARGET_DARWIN_OSX) + EXPECT_EQ(g_sysinfo.GetUserAgent().find('('), g_sysinfo.GetUserAgent().find("(Macintosh; ")) << "Second parameter in 'GetUserAgent()' string must start from 'Macintosh; '"; +#elif defined(TARGET_ANDROID) + EXPECT_EQ(g_sysinfo.GetUserAgent().find('('), g_sysinfo.GetUserAgent().find("(Linux; Android ")) << "Second parameter in 'GetUserAgent()' string must start from 'Linux; Android '"; +#elif defined(TARGET_POSIX) + EXPECT_EQ(g_sysinfo.GetUserAgent().find('('), g_sysinfo.GetUserAgent().find("(X11; ")) << "Second parameter in 'GetUserAgent()' string must start from 'X11; '"; +#if defined(TARGET_FREEBSD) + EXPECT_EQ(g_sysinfo.GetUserAgent().find('('), g_sysinfo.GetUserAgent().find("(X11; FreeBSD ")) << "Second parameter in 'GetUserAgent()' string must start from 'X11; FreeBSD '"; +#elif defined(TARGET_LINUX) + EXPECT_EQ(g_sysinfo.GetUserAgent().find('('), g_sysinfo.GetUserAgent().find("(X11; Linux ")) << "Second parameter in 'GetUserAgent()' string must start from 'X11; Linux '"; +#endif // defined(TARGET_LINUX) +#endif // defined(TARGET_POSIX) + + EXPECT_NE(std::string::npos, g_sysinfo.GetUserAgent().find(" App_Bitness/")) << "'GetUserAgent()' must contain ' App_Bitness/'"; + EXPECT_NE(std::string::npos, g_sysinfo.GetUserAgent().find(" Version/")) << "'GetUserAgent()' must contain ' Version/'"; +} + +TEST_F(TestSystemInfo, GetBuildTargetPlatformName) +{ + EXPECT_EQ(std::string::npos, g_sysinfo.GetBuildTargetPlatformName().find("Unknown")) << "'GetBuildTargetPlatformName()' must not contain 'Unknown', actual value: '" << g_sysinfo.GetBuildTargetPlatformName() << "'"; + EXPECT_EQ(std::string::npos, g_sysinfo.GetBuildTargetPlatformName().find("unknown")) << "'GetBuildTargetPlatformName()' must not contain 'unknown', actual value: '" << g_sysinfo.GetBuildTargetPlatformName() << "'"; +} + +TEST_F(TestSystemInfo, GetBuildTargetPlatformVersion) +{ + EXPECT_EQ(std::string::npos, g_sysinfo.GetBuildTargetPlatformVersion().find("Unknown")) << "'GetBuildTargetPlatformVersion()' must not contain 'Unknown', actual value: '" << g_sysinfo.GetBuildTargetPlatformVersion() << "'"; + EXPECT_EQ(std::string::npos, g_sysinfo.GetBuildTargetPlatformVersion().find("unknown")) << "'GetBuildTargetPlatformVersion()' must not contain 'unknown', actual value: '" << g_sysinfo.GetBuildTargetPlatformVersion() << "'"; +} + +TEST_F(TestSystemInfo, GetBuildTargetPlatformVersionDecoded) +{ + EXPECT_EQ(std::string::npos, g_sysinfo.GetBuildTargetPlatformVersionDecoded().find("Unknown")) << "'GetBuildTargetPlatformVersionDecoded()' must not contain 'Unknown', actual value: '" << g_sysinfo.GetBuildTargetPlatformVersion() << "'"; + EXPECT_EQ(std::string::npos, g_sysinfo.GetBuildTargetPlatformVersionDecoded().find("unknown")) << "'GetBuildTargetPlatformVersionDecoded()' must not contain 'unknown', actual value: '" << g_sysinfo.GetBuildTargetPlatformVersion() << "'"; +#ifdef TARGET_ANDROID + EXPECT_STREQ("API level ", g_sysinfo.GetBuildTargetPlatformVersionDecoded().substr(0, 10).c_str()) << "'GetBuildTargetPlatformVersionDecoded()' must start from 'API level '"; +#else + EXPECT_STREQ("version ", g_sysinfo.GetBuildTargetPlatformVersionDecoded().substr(0, 8).c_str()) << "'GetBuildTargetPlatformVersionDecoded()' must start from 'version'"; +#endif +} + +TEST_F(TestSystemInfo, GetBuildTargetCpuFamily) +{ + EXPECT_STRNE("unknown CPU family", g_sysinfo.GetBuildTargetCpuFamily().c_str()) << "'GetBuildTargetCpuFamily()' must not return 'unknown CPU family'"; +#if defined(__thumb__) || defined(_M_ARMT) || defined(__arm__) || defined(_M_ARM) || defined (__aarch64__) + EXPECT_STREQ("ARM", g_sysinfo.GetBuildTargetCpuFamily().substr(0, 3).c_str()) << "'GetKernelCpuFamily()' string must start from 'ARM'"; +#else // ! ARM + EXPECT_EQ(g_sysinfo.GetKernelCpuFamily(), g_sysinfo.GetBuildTargetCpuFamily()) << "'GetBuildTargetCpuFamily()' must match 'GetKernelCpuFamily()'"; +#endif // ! ARM +} + +TEST_F(TestSystemInfo, GetUsedCompilerNameAndVer) +{ + EXPECT_STRNE("unknown compiler", g_sysinfo.GetUsedCompilerNameAndVer().c_str()) << "'GetUsedCompilerNameAndVer()' must not return 'unknown compiler'"; +} + +TEST_F(TestSystemInfo, GetDiskSpace) +{ + int iTotal, iTotalFree, iTotalUsed, iPercentFree, iPercentUsed; + + iTotal = iTotalFree = iTotalUsed = iPercentFree = iPercentUsed = 0; + EXPECT_TRUE(g_sysinfo.GetDiskSpace("*", iTotal, iTotalFree, iTotalUsed, iPercentFree, iPercentUsed)) << "'GetDiskSpace()' return 'false' for disk '*'"; + EXPECT_NE(0, iTotal) << "'GetDiskSpace()' return zero total space for disk '*'"; + EXPECT_EQ(iTotal, iTotalFree + iTotalUsed) << "'GetDiskSpace()' return 'TotalFree + TotalUsed' not equal to 'Total' for disk '*'"; + EXPECT_EQ(100, iPercentFree + iPercentUsed) << "'GetDiskSpace()' return 'PercentFree + PercentUsed' not equal to '100' for disk '*'"; + + iTotal = iTotalFree = iTotalUsed = iPercentFree = iPercentUsed = 0; + EXPECT_TRUE(g_sysinfo.GetDiskSpace("", iTotal, iTotalFree, iTotalUsed, iPercentFree, iPercentUsed)) << "'GetDiskSpace()' return 'false' for disk ''"; + EXPECT_NE(0, iTotal) << "'GetDiskSpace()' return zero total space for disk ''"; + EXPECT_EQ(iTotal, iTotalFree + iTotalUsed) << "'GetDiskSpace()' return 'TotalFree + TotalUsed' not equal to 'Total' for disk ''"; + EXPECT_EQ(100, iPercentFree + iPercentUsed) << "'GetDiskSpace()' return 'PercentFree + PercentUsed' not equal to '100' for disk ''"; + +#ifdef TARGET_WINDOWS + using KODI::PLATFORM::WINDOWS::FromW; + wchar_t sysDrive[300]; + DWORD res = GetEnvironmentVariableW(L"SystemDrive", sysDrive, sizeof(sysDrive) / sizeof(wchar_t)); + std::string sysDriveLtr; + if (res != 0 && res <= sizeof(sysDrive) / sizeof(wchar_t)) + sysDriveLtr.assign(FromW(sysDrive), 0, 1); + else + sysDriveLtr = "C"; // fallback + + iTotal = iTotalFree = iTotalUsed = iPercentFree = iPercentUsed = 0; + EXPECT_TRUE(g_sysinfo.GetDiskSpace(sysDriveLtr, iTotal, iTotalFree, iTotalUsed, iPercentFree, iPercentUsed)) << "'GetDiskSpace()' return 'false' for disk '" << sysDriveLtr << ":'"; + EXPECT_NE(0, iTotal) << "'GetDiskSpace()' return zero total space for disk '" << sysDriveLtr << ":'"; + EXPECT_EQ(iTotal, iTotalFree + iTotalUsed) << "'GetDiskSpace()' return 'TotalFree + TotalUsed' not equal to 'Total' for disk '" << sysDriveLtr << ":'"; + EXPECT_EQ(100, iPercentFree + iPercentUsed) << "'GetDiskSpace()' return 'PercentFree + PercentUsed' not equal to '100' for disk '" << sysDriveLtr << ":'"; +#elif defined(TARGET_POSIX) + iTotal = iTotalFree = iTotalUsed = iPercentFree = iPercentUsed = 0; + EXPECT_TRUE(g_sysinfo.GetDiskSpace("/", iTotal, iTotalFree, iTotalUsed, iPercentFree, iPercentUsed)) << "'GetDiskSpace()' return 'false' for directory '/'"; + EXPECT_NE(0, iTotal) << "'GetDiskSpace()' return zero total space for directory '/'"; + EXPECT_EQ(iTotal, iTotalFree + iTotalUsed) << "'GetDiskSpace()' return 'TotalFree + TotalUsed' not equal to 'Total' for directory '/'"; + EXPECT_EQ(100, iPercentFree + iPercentUsed) << "'GetDiskSpace()' return 'PercentFree + PercentUsed' not equal to '100' for directory '/'"; +#endif +} diff --git a/xbmc/utils/test/TestURIUtils.cpp b/xbmc/utils/test/TestURIUtils.cpp new file mode 100644 index 0000000..7122fe9 --- /dev/null +++ b/xbmc/utils/test/TestURIUtils.cpp @@ -0,0 +1,585 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "ServiceBroker.h" +#include "URL.h" +#include "filesystem/MultiPathDirectory.h" +#include "settings/AdvancedSettings.h" +#include "settings/SettingsComponent.h" +#include "utils/URIUtils.h" + +#include <utility> + +#include <gtest/gtest.h> + +using namespace XFILE; + +class TestURIUtils : public testing::Test +{ +protected: + TestURIUtils() = default; + ~TestURIUtils() override + { + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_pathSubstitutions.clear(); + } +}; + +TEST_F(TestURIUtils, PathHasParent) +{ + EXPECT_TRUE(URIUtils::PathHasParent("/path/to/movie.avi", "/path/to/")); + EXPECT_FALSE(URIUtils::PathHasParent("/path/to/movie.avi", "/path/2/")); +} + +TEST_F(TestURIUtils, GetDirectory) +{ + EXPECT_STREQ("/path/to/", URIUtils::GetDirectory("/path/to/movie.avi").c_str()); + EXPECT_STREQ("/path/to/", URIUtils::GetDirectory("/path/to/").c_str()); + EXPECT_STREQ("/path/to/|option=foo", URIUtils::GetDirectory("/path/to/movie.avi|option=foo").c_str()); + EXPECT_STREQ("/path/to/|option=foo", URIUtils::GetDirectory("/path/to/|option=foo").c_str()); + EXPECT_STREQ("", URIUtils::GetDirectory("movie.avi").c_str()); + EXPECT_STREQ("", URIUtils::GetDirectory("movie.avi|option=foo").c_str()); + EXPECT_STREQ("", URIUtils::GetDirectory("").c_str()); + + // Make sure it works when assigning to the same str as the reference parameter + std::string var = "/path/to/movie.avi|option=foo"; + var = URIUtils::GetDirectory(var); + EXPECT_STREQ("/path/to/|option=foo", var.c_str()); +} + +TEST_F(TestURIUtils, GetExtension) +{ + EXPECT_STREQ(".avi", + URIUtils::GetExtension("/path/to/movie.avi").c_str()); +} + +TEST_F(TestURIUtils, HasExtension) +{ + EXPECT_TRUE (URIUtils::HasExtension("/path/to/movie.AvI")); + EXPECT_FALSE(URIUtils::HasExtension("/path/to/movie")); + EXPECT_FALSE(URIUtils::HasExtension("/path/.to/movie")); + EXPECT_FALSE(URIUtils::HasExtension("")); + + EXPECT_TRUE (URIUtils::HasExtension("/path/to/movie.AvI", ".avi")); + EXPECT_FALSE(URIUtils::HasExtension("/path/to/movie.AvI", ".mkv")); + EXPECT_FALSE(URIUtils::HasExtension("/path/.avi/movie", ".avi")); + EXPECT_FALSE(URIUtils::HasExtension("", ".avi")); + + EXPECT_TRUE (URIUtils::HasExtension("/path/movie.AvI", ".avi|.mkv|.mp4")); + EXPECT_TRUE (URIUtils::HasExtension("/path/movie.AvI", ".mkv|.avi|.mp4")); + EXPECT_FALSE(URIUtils::HasExtension("/path/movie.AvI", ".mpg|.mkv|.mp4")); + EXPECT_FALSE(URIUtils::HasExtension("/path.mkv/movie.AvI", ".mpg|.mkv|.mp4")); + EXPECT_FALSE(URIUtils::HasExtension("", ".avi|.mkv|.mp4")); +} + +TEST_F(TestURIUtils, GetFileName) +{ + EXPECT_STREQ("movie.avi", + URIUtils::GetFileName("/path/to/movie.avi").c_str()); +} + +TEST_F(TestURIUtils, RemoveExtension) +{ + std::string ref, var; + + /* NOTE: CSettings need to be set to find other extensions. */ + ref = "/path/to/file"; + var = "/path/to/file.xml"; + URIUtils::RemoveExtension(var); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST_F(TestURIUtils, ReplaceExtension) +{ + std::string ref, var; + + ref = "/path/to/file.xsd"; + var = URIUtils::ReplaceExtension("/path/to/file.xml", ".xsd"); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST_F(TestURIUtils, Split) +{ + std::string refpath, reffile, varpath, varfile; + + refpath = "/path/to/"; + reffile = "movie.avi"; + URIUtils::Split("/path/to/movie.avi", varpath, varfile); + EXPECT_STREQ(refpath.c_str(), varpath.c_str()); + EXPECT_STREQ(reffile.c_str(), varfile.c_str()); + + std::string varpathOptional, varfileOptional; + + refpath = "/path/to/"; + reffile = "movie?movie.avi"; + URIUtils::Split("/path/to/movie?movie.avi", varpathOptional, varfileOptional); + EXPECT_STREQ(refpath.c_str(), varpathOptional.c_str()); + EXPECT_STREQ(reffile.c_str(), varfileOptional.c_str()); + + refpath = "file:///path/to/"; + reffile = "movie.avi"; + URIUtils::Split("file:///path/to/movie.avi?showinfo=true", varpathOptional, varfileOptional); + EXPECT_STREQ(refpath.c_str(), varpathOptional.c_str()); + EXPECT_STREQ(reffile.c_str(), varfileOptional.c_str()); +} + +TEST_F(TestURIUtils, SplitPath) +{ + std::vector<std::string> strarray; + + strarray = URIUtils::SplitPath("http://www.test.com/path/to/movie.avi"); + + EXPECT_STREQ("http://www.test.com/", strarray.at(0).c_str()); + EXPECT_STREQ("path", strarray.at(1).c_str()); + EXPECT_STREQ("to", strarray.at(2).c_str()); + EXPECT_STREQ("movie.avi", strarray.at(3).c_str()); +} + +TEST_F(TestURIUtils, SplitPathLocal) +{ +#ifndef TARGET_LINUX + const char *path = "C:\\path\\to\\movie.avi"; +#else + const char *path = "/path/to/movie.avi"; +#endif + std::vector<std::string> strarray; + + strarray = URIUtils::SplitPath(path); + +#ifndef TARGET_LINUX + EXPECT_STREQ("C:", strarray.at(0).c_str()); +#else + EXPECT_STREQ("", strarray.at(0).c_str()); +#endif + EXPECT_STREQ("path", strarray.at(1).c_str()); + EXPECT_STREQ("to", strarray.at(2).c_str()); + EXPECT_STREQ("movie.avi", strarray.at(3).c_str()); +} + +TEST_F(TestURIUtils, GetCommonPath) +{ + std::string ref, var; + + ref = "/path/"; + var = "/path/2/movie.avi"; + URIUtils::GetCommonPath(var, "/path/to/movie.avi"); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST_F(TestURIUtils, GetParentPath) +{ + std::string ref, var; + + ref = "/path/to/"; + var = URIUtils::GetParentPath("/path/to/movie.avi"); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + var.clear(); + EXPECT_TRUE(URIUtils::GetParentPath("/path/to/movie.avi", var)); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST_F(TestURIUtils, SubstitutePath) +{ + std::string from, to, ref, var; + + from = "C:\\My Videos"; + to = "https://myserver/some%20other%20path"; + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_pathSubstitutions.push_back(std::make_pair(from, to)); + + from = "/this/path1"; + to = "/some/other/path2"; + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_pathSubstitutions.push_back(std::make_pair(from, to)); + + from = "davs://otherserver/my%20music%20path"; + to = "D:\\Local Music\\MP3 Collection"; + CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_pathSubstitutions.push_back(std::make_pair(from, to)); + + ref = "https://myserver/some%20other%20path/sub%20dir/movie%20name.avi"; + var = URIUtils::SubstitutePath("C:\\My Videos\\sub dir\\movie name.avi"); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "C:\\My Videos\\sub dir\\movie name.avi"; + var = URIUtils::SubstitutePath("https://myserver/some%20other%20path/sub%20dir/movie%20name.avi", true); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "D:\\Local Music\\MP3 Collection\\Phil Collins\\Some CD\\01 - Two Hearts.mp3"; + var = URIUtils::SubstitutePath("davs://otherserver/my%20music%20path/Phil%20Collins/Some%20CD/01%20-%20Two%20Hearts.mp3"); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "davs://otherserver/my%20music%20path/Phil%20Collins/Some%20CD/01%20-%20Two%20Hearts.mp3"; + var = URIUtils::SubstitutePath("D:\\Local Music\\MP3 Collection\\Phil Collins\\Some CD\\01 - Two Hearts.mp3", true); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "/some/other/path2/to/movie.avi"; + var = URIUtils::SubstitutePath("/this/path1/to/movie.avi"); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "/this/path1/to/movie.avi"; + var = URIUtils::SubstitutePath("/some/other/path2/to/movie.avi", true); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "/no/translation path/"; + var = URIUtils::SubstitutePath(ref); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "/no/translation path/"; + var = URIUtils::SubstitutePath(ref, true); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "c:\\no\\translation path"; + var = URIUtils::SubstitutePath(ref); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "c:\\no\\translation path"; + var = URIUtils::SubstitutePath(ref, true); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST_F(TestURIUtils, IsAddonsPath) +{ + EXPECT_TRUE(URIUtils::IsAddonsPath("addons://path/to/addons")); +} + +TEST_F(TestURIUtils, IsSourcesPath) +{ + EXPECT_TRUE(URIUtils::IsSourcesPath("sources://path/to/sources")); +} + +TEST_F(TestURIUtils, IsCDDA) +{ + EXPECT_TRUE(URIUtils::IsCDDA("cdda://path/to/cdda")); +} + +TEST_F(TestURIUtils, IsDOSPath) +{ + EXPECT_TRUE(URIUtils::IsDOSPath("C://path/to/dosfile")); +} + +TEST_F(TestURIUtils, IsDVD) +{ + EXPECT_TRUE(URIUtils::IsDVD("dvd://path/in/video_ts.ifo")); +#if defined(TARGET_WINDOWS) + EXPECT_TRUE(URIUtils::IsDVD("dvd://path/in/file")); +#else + EXPECT_TRUE(URIUtils::IsDVD("iso9660://path/in/video_ts.ifo")); + EXPECT_TRUE(URIUtils::IsDVD("udf://path/in/video_ts.ifo")); + EXPECT_TRUE(URIUtils::IsDVD("dvd://1")); +#endif +} + +TEST_F(TestURIUtils, IsFTP) +{ + EXPECT_TRUE(URIUtils::IsFTP("ftp://path/in/ftp")); +} + +TEST_F(TestURIUtils, IsHD) +{ + EXPECT_TRUE(URIUtils::IsHD("/path/to/file")); + EXPECT_TRUE(URIUtils::IsHD("file:///path/to/file")); + EXPECT_TRUE(URIUtils::IsHD("special://path/to/file")); + EXPECT_TRUE(URIUtils::IsHD("stack://path/to/file")); + EXPECT_TRUE(URIUtils::IsHD("zip://path/to/file")); +} + +TEST_F(TestURIUtils, IsInArchive) +{ + EXPECT_TRUE(URIUtils::IsInArchive("zip://path/to/file")); +} + +TEST_F(TestURIUtils, IsInRAR) +{ + EXPECT_TRUE(URIUtils::IsInRAR("rar://path/to/file")); +} + +TEST_F(TestURIUtils, IsInternetStream) +{ + CURL url1("http://path/to/file"); + CURL url2("https://path/to/file"); + EXPECT_TRUE(URIUtils::IsInternetStream(url1)); + EXPECT_TRUE(URIUtils::IsInternetStream(url2)); +} + +TEST_F(TestURIUtils, IsInZIP) +{ + EXPECT_TRUE(URIUtils::IsInZIP("zip://path/to/file")); +} + +TEST_F(TestURIUtils, IsISO9660) +{ + EXPECT_TRUE(URIUtils::IsISO9660("iso9660://path/to/file")); +} + +TEST_F(TestURIUtils, IsLiveTV) +{ + EXPECT_TRUE(URIUtils::IsLiveTV("whatever://path/to/file.pvr")); +} + +TEST_F(TestURIUtils, IsMultiPath) +{ + EXPECT_TRUE(URIUtils::IsMultiPath("multipath://path/to/file")); +} + +TEST_F(TestURIUtils, IsMusicDb) +{ + EXPECT_TRUE(URIUtils::IsMusicDb("musicdb://path/to/file")); +} + +TEST_F(TestURIUtils, IsNfs) +{ + EXPECT_TRUE(URIUtils::IsNfs("nfs://path/to/file")); + EXPECT_TRUE(URIUtils::IsNfs("stack://nfs://path/to/file")); +} + +TEST_F(TestURIUtils, IsOnDVD) +{ + EXPECT_TRUE(URIUtils::IsOnDVD("dvd://path/to/file")); + EXPECT_TRUE(URIUtils::IsOnDVD("udf://path/to/file")); + EXPECT_TRUE(URIUtils::IsOnDVD("iso9660://path/to/file")); + EXPECT_TRUE(URIUtils::IsOnDVD("cdda://path/to/file")); +} + +TEST_F(TestURIUtils, IsOnLAN) +{ + std::vector<std::string> multiVec; + multiVec.emplace_back("smb://path/to/file"); + EXPECT_TRUE(URIUtils::IsOnLAN(CMultiPathDirectory::ConstructMultiPath(multiVec))); + EXPECT_TRUE(URIUtils::IsOnLAN("stack://smb://path/to/file")); + EXPECT_TRUE(URIUtils::IsOnLAN("smb://path/to/file")); + EXPECT_FALSE(URIUtils::IsOnLAN("plugin://path/to/file")); + EXPECT_TRUE(URIUtils::IsOnLAN("upnp://path/to/file")); +} + +TEST_F(TestURIUtils, IsPlugin) +{ + EXPECT_TRUE(URIUtils::IsPlugin("plugin://path/to/file")); +} + +TEST_F(TestURIUtils, IsScript) +{ + EXPECT_TRUE(URIUtils::IsScript("script://path/to/file")); +} + +TEST_F(TestURIUtils, IsRAR) +{ + EXPECT_TRUE(URIUtils::IsRAR("/path/to/rarfile.rar")); + EXPECT_TRUE(URIUtils::IsRAR("/path/to/rarfile.cbr")); + EXPECT_FALSE(URIUtils::IsRAR("/path/to/file")); + EXPECT_FALSE(URIUtils::IsRAR("rar://path/to/file")); +} + +TEST_F(TestURIUtils, IsRemote) +{ + EXPECT_TRUE(URIUtils::IsRemote("http://path/to/file")); + EXPECT_TRUE(URIUtils::IsRemote("https://path/to/file")); + EXPECT_FALSE(URIUtils::IsRemote("addons://user/")); + EXPECT_FALSE(URIUtils::IsRemote("sources://video/")); + EXPECT_FALSE(URIUtils::IsRemote("videodb://movies/titles")); + EXPECT_FALSE(URIUtils::IsRemote("musicdb://genres/")); + EXPECT_FALSE(URIUtils::IsRemote("library://video/")); + EXPECT_FALSE(URIUtils::IsRemote("androidapp://app")); + EXPECT_FALSE(URIUtils::IsRemote("plugin://plugin.video.id")); +} + +TEST_F(TestURIUtils, IsSmb) +{ + EXPECT_TRUE(URIUtils::IsSmb("smb://path/to/file")); + EXPECT_TRUE(URIUtils::IsSmb("stack://smb://path/to/file")); +} + +TEST_F(TestURIUtils, IsSpecial) +{ + EXPECT_TRUE(URIUtils::IsSpecial("special://path/to/file")); + EXPECT_TRUE(URIUtils::IsSpecial("stack://special://path/to/file")); +} + +TEST_F(TestURIUtils, IsStack) +{ + EXPECT_TRUE(URIUtils::IsStack("stack://path/to/file")); +} + +TEST_F(TestURIUtils, IsUPnP) +{ + EXPECT_TRUE(URIUtils::IsUPnP("upnp://path/to/file")); +} + +TEST_F(TestURIUtils, IsURL) +{ + EXPECT_TRUE(URIUtils::IsURL("someprotocol://path/to/file")); + EXPECT_FALSE(URIUtils::IsURL("/path/to/file")); +} + +TEST_F(TestURIUtils, IsVideoDb) +{ + EXPECT_TRUE(URIUtils::IsVideoDb("videodb://path/to/file")); +} + +TEST_F(TestURIUtils, IsZIP) +{ + EXPECT_TRUE(URIUtils::IsZIP("/path/to/zipfile.zip")); + EXPECT_TRUE(URIUtils::IsZIP("/path/to/zipfile.cbz")); + EXPECT_FALSE(URIUtils::IsZIP("/path/to/file")); + EXPECT_FALSE(URIUtils::IsZIP("zip://path/to/file")); +} + +TEST_F(TestURIUtils, IsBluray) +{ + EXPECT_TRUE(URIUtils::IsBluray("bluray://path/to/file")); +} + +TEST_F(TestURIUtils, AddSlashAtEnd) +{ + std::string ref, var; + + ref = "bluray://path/to/file/"; + var = "bluray://path/to/file/"; + URIUtils::AddSlashAtEnd(var); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST_F(TestURIUtils, HasSlashAtEnd) +{ + EXPECT_TRUE(URIUtils::HasSlashAtEnd("bluray://path/to/file/")); + EXPECT_FALSE(URIUtils::HasSlashAtEnd("bluray://path/to/file")); +} + +TEST_F(TestURIUtils, RemoveSlashAtEnd) +{ + std::string ref, var; + + ref = "bluray://path/to/file"; + var = "bluray://path/to/file/"; + URIUtils::RemoveSlashAtEnd(var); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST_F(TestURIUtils, CreateArchivePath) +{ + std::string ref, var; + + ref = "zip://%2fpath%2fto%2f/file"; + var = URIUtils::CreateArchivePath("zip", CURL("/path/to/"), "file").Get(); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST_F(TestURIUtils, AddFileToFolder) +{ + std::string ref = "/path/to/file"; + std::string var = URIUtils::AddFileToFolder("/path/to", "file"); + EXPECT_STREQ(ref.c_str(), var.c_str()); + + ref = "/path/to/file/and/more"; + var = URIUtils::AddFileToFolder("/path", "to", "file", "and", "more"); + EXPECT_STREQ(ref.c_str(), var.c_str()); +} + +TEST_F(TestURIUtils, HasParentInHostname) +{ + EXPECT_TRUE(URIUtils::HasParentInHostname(CURL("zip://"))); + EXPECT_TRUE(URIUtils::HasParentInHostname(CURL("bluray://"))); +} + +TEST_F(TestURIUtils, HasEncodedHostname) +{ + EXPECT_TRUE(URIUtils::HasEncodedHostname(CURL("zip://"))); + EXPECT_TRUE(URIUtils::HasEncodedHostname(CURL("bluray://"))); + EXPECT_TRUE(URIUtils::HasEncodedHostname(CURL("musicsearch://"))); +} + +TEST_F(TestURIUtils, HasEncodedFilename) +{ + EXPECT_TRUE(URIUtils::HasEncodedFilename(CURL("shout://"))); + EXPECT_TRUE(URIUtils::HasEncodedFilename(CURL("dav://"))); + EXPECT_TRUE(URIUtils::HasEncodedFilename(CURL("rss://"))); + EXPECT_TRUE(URIUtils::HasEncodedFilename(CURL("davs://"))); +} + +TEST_F(TestURIUtils, GetRealPath) +{ + std::string ref; + + ref = "/path/to/file/"; + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath(ref).c_str()); + + ref = "path/to/file"; + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("../path/to/file").c_str()); + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("./path/to/file").c_str()); + + ref = "/path/to/file"; + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath(ref).c_str()); + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("/path/to/./file").c_str()); + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("/./path/to/./file").c_str()); + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("/path/to/some/../file").c_str()); + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("/../path/to/some/../file").c_str()); + + ref = "/path/to"; + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("/path/to/some/../file/..").c_str()); + +#ifdef TARGET_WINDOWS + ref = "\\\\path\\to\\file\\"; + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath(ref).c_str()); + + ref = "path\\to\\file"; + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("..\\path\\to\\file").c_str()); + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath(".\\path\\to\\file").c_str()); + + ref = "\\\\path\\to\\file"; + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath(ref).c_str()); + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("\\\\path\\to\\.\\file").c_str()); + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("\\\\.\\path/to\\.\\file").c_str()); + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("\\\\path\\to\\some\\..\\file").c_str()); + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("\\\\..\\path\\to\\some\\..\\file").c_str()); + + ref = "\\\\path\\to"; + EXPECT_STREQ(ref.c_str(), URIUtils::GetRealPath("\\\\path\\to\\some\\..\\file\\..").c_str()); +#endif + + // test rar/zip paths + ref = "zip://%2fpath%2fto%2fzip/subpath/to/file"; + EXPECT_STRCASEEQ(ref.c_str(), URIUtils::GetRealPath(ref).c_str()); + + // test rar/zip paths + ref = "zip://%2fpath%2fto%2fzip/subpath/to/file"; + EXPECT_STRCASEEQ(ref.c_str(), URIUtils::GetRealPath("zip://%2fpath%2fto%2fzip/../subpath/to/file").c_str()); + EXPECT_STRCASEEQ(ref.c_str(), URIUtils::GetRealPath("zip://%2fpath%2fto%2fzip/./subpath/to/file").c_str()); + EXPECT_STRCASEEQ(ref.c_str(), URIUtils::GetRealPath("zip://%2fpath%2fto%2fzip/subpath/to/./file").c_str()); + EXPECT_STRCASEEQ(ref.c_str(), URIUtils::GetRealPath("zip://%2fpath%2fto%2fzip/subpath/to/some/../file").c_str()); + + EXPECT_STRCASEEQ(ref.c_str(), URIUtils::GetRealPath("zip://%2fpath%2fto%2f.%2fzip/subpath/to/file").c_str()); + EXPECT_STRCASEEQ(ref.c_str(), URIUtils::GetRealPath("zip://%2fpath%2fto%2fsome%2f..%2fzip/subpath/to/file").c_str()); + + // test zip/zip path + ref ="zip://zip%3a%2f%2f%252Fpath%252Fto%252Fzip%2fpath%2fto%2fzip/subpath/to/file"; + EXPECT_STRCASEEQ(ref.c_str(), URIUtils::GetRealPath("zip://zip%3a%2f%2f%252Fpath%252Fto%252Fsome%252F..%252Fzip%2fpath%2fto%2fsome%2f..%2fzip/subpath/to/some/../file").c_str()); +} + +TEST_F(TestURIUtils, UpdateUrlEncoding) +{ + std::string oldUrl = "stack://zip://%2fpath%2fto%2farchive%2fsome%2darchive%2dfile%2eCD1%2ezip/video.avi , zip://%2fpath%2fto%2farchive%2fsome%2darchive%2dfile%2eCD2%2ezip/video.avi"; + std::string newUrl = "stack://zip://%2fpath%2fto%2farchive%2fsome-archive-file.CD1.zip/video.avi , zip://%2fpath%2fto%2farchive%2fsome-archive-file.CD2.zip/video.avi"; + + EXPECT_TRUE(URIUtils::UpdateUrlEncoding(oldUrl)); + EXPECT_STRCASEEQ(newUrl.c_str(), oldUrl.c_str()); + + oldUrl = "zip://%2fpath%2fto%2farchive%2fsome%2darchive%2efile%2ezip/video.avi"; + newUrl = "zip://%2fpath%2fto%2farchive%2fsome-archive.file.zip/video.avi"; + + EXPECT_TRUE(URIUtils::UpdateUrlEncoding(oldUrl)); + EXPECT_STRCASEEQ(newUrl.c_str(), oldUrl.c_str()); + + oldUrl = "/path/to/some/long%2dnamed%2efile"; + newUrl = "/path/to/some/long%2dnamed%2efile"; + + EXPECT_FALSE(URIUtils::UpdateUrlEncoding(oldUrl)); + EXPECT_STRCASEEQ(newUrl.c_str(), oldUrl.c_str()); + + oldUrl = "/path/to/some/long-named.file"; + newUrl = "/path/to/some/long-named.file"; + + EXPECT_FALSE(URIUtils::UpdateUrlEncoding(oldUrl)); + EXPECT_STRCASEEQ(newUrl.c_str(), oldUrl.c_str()); +} diff --git a/xbmc/utils/test/TestUrlOptions.cpp b/xbmc/utils/test/TestUrlOptions.cpp new file mode 100644 index 0000000..f684fe5 --- /dev/null +++ b/xbmc/utils/test/TestUrlOptions.cpp @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/UrlOptions.h" +#include "utils/Variant.h" + +#include <gtest/gtest.h> + +TEST(TestUrlOptions, Clear) +{ + const char *key = "foo"; + + CUrlOptions urlOptions; + urlOptions.AddOption(key, "bar"); + EXPECT_TRUE(urlOptions.HasOption(key)); + + urlOptions.Clear(); + EXPECT_FALSE(urlOptions.HasOption(key)); +} + +TEST(TestUrlOptions, AddOption) +{ + const char *keyChar = "char"; + const char *keyString = "string"; + const char *keyEmpty = "empty"; + const char *keyInt = "int"; + const char *keyFloat = "float"; + const char *keyDouble = "double"; + const char *keyBool = "bool"; + + const char *valueChar = "valueChar"; + const std::string valueString = "valueString"; + const char *valueEmpty = ""; + int valueInt = 1; + float valueFloat = 1.0f; + double valueDouble = 1.0; + bool valueBool = true; + + CVariant variantValue; + + CUrlOptions urlOptions; + urlOptions.AddOption(keyChar, valueChar); + { + CVariant variantValue; + EXPECT_TRUE(urlOptions.GetOption(keyChar, variantValue)); + EXPECT_TRUE(variantValue.isString()); + EXPECT_STREQ(valueChar, variantValue.asString().c_str()); + } + + urlOptions.AddOption(keyString, valueString); + { + CVariant variantValue; + EXPECT_TRUE(urlOptions.GetOption(keyString, variantValue)); + EXPECT_TRUE(variantValue.isString()); + EXPECT_STREQ(valueString.c_str(), variantValue.asString().c_str()); + } + + urlOptions.AddOption(keyEmpty, valueEmpty); + { + CVariant variantValue; + EXPECT_TRUE(urlOptions.GetOption(keyEmpty, variantValue)); + EXPECT_TRUE(variantValue.isString()); + EXPECT_STREQ(valueEmpty, variantValue.asString().c_str()); + } + + urlOptions.AddOption(keyInt, valueInt); + { + CVariant variantValue; + EXPECT_TRUE(urlOptions.GetOption(keyInt, variantValue)); + EXPECT_TRUE(variantValue.isInteger()); + EXPECT_EQ(valueInt, (int)variantValue.asInteger()); + } + + urlOptions.AddOption(keyFloat, valueFloat); + { + CVariant variantValue; + EXPECT_TRUE(urlOptions.GetOption(keyFloat, variantValue)); + EXPECT_TRUE(variantValue.isDouble()); + EXPECT_EQ(valueFloat, variantValue.asFloat()); + } + + urlOptions.AddOption(keyDouble, valueDouble); + { + CVariant variantValue; + EXPECT_TRUE(urlOptions.GetOption(keyDouble, variantValue)); + EXPECT_TRUE(variantValue.isDouble()); + EXPECT_EQ(valueDouble, variantValue.asDouble()); + } + + urlOptions.AddOption(keyBool, valueBool); + { + CVariant variantValue; + EXPECT_TRUE(urlOptions.GetOption(keyBool, variantValue)); + EXPECT_TRUE(variantValue.isBoolean()); + EXPECT_EQ(valueBool, variantValue.asBoolean()); + } +} + +TEST(TestUrlOptions, AddOptions) +{ + std::string ref = "foo=bar&key=value"; + + CUrlOptions urlOptions(ref); + { + CVariant value; + EXPECT_TRUE(urlOptions.GetOption("foo", value)); + EXPECT_TRUE(value.isString()); + EXPECT_STREQ("bar", value.asString().c_str()); + } + { + CVariant value; + EXPECT_TRUE(urlOptions.GetOption("key", value)); + EXPECT_TRUE(value.isString()); + EXPECT_STREQ("value", value.asString().c_str()); + } + + ref = "foo=bar&key"; + urlOptions.Clear(); + urlOptions.AddOptions(ref); + { + CVariant value; + EXPECT_TRUE(urlOptions.GetOption("foo", value)); + EXPECT_TRUE(value.isString()); + EXPECT_STREQ("bar", value.asString().c_str()); + } + { + CVariant value; + EXPECT_TRUE(urlOptions.GetOption("key", value)); + EXPECT_TRUE(value.isString()); + EXPECT_TRUE(value.empty()); + } +} + +TEST(TestUrlOptions, RemoveOption) +{ + const char *key = "foo"; + + CUrlOptions urlOptions; + urlOptions.AddOption(key, "bar"); + EXPECT_TRUE(urlOptions.HasOption(key)); + + urlOptions.RemoveOption(key); + EXPECT_FALSE(urlOptions.HasOption(key)); +} + +TEST(TestUrlOptions, HasOption) +{ + const char *key = "foo"; + + CUrlOptions urlOptions; + urlOptions.AddOption(key, "bar"); + EXPECT_TRUE(urlOptions.HasOption(key)); + EXPECT_FALSE(urlOptions.HasOption("bar")); +} + +TEST(TestUrlOptions, GetOptions) +{ + const char *key1 = "foo"; + const char *key2 = "key"; + const char *value1 = "bar"; + const char *value2 = "value"; + + CUrlOptions urlOptions; + urlOptions.AddOption(key1, value1); + urlOptions.AddOption(key2, value2); + const CUrlOptions::UrlOptions &options = urlOptions.GetOptions(); + EXPECT_FALSE(options.empty()); + EXPECT_EQ(2U, options.size()); + + CUrlOptions::UrlOptions::const_iterator it1 = options.find(key1); + EXPECT_TRUE(it1 != options.end()); + CUrlOptions::UrlOptions::const_iterator it2 = options.find(key2); + EXPECT_TRUE(it2 != options.end()); + EXPECT_FALSE(options.find("wrong") != options.end()); + EXPECT_TRUE(it1->second.isString()); + EXPECT_TRUE(it2->second.isString()); + EXPECT_STREQ(value1, it1->second.asString().c_str()); + EXPECT_STREQ(value2, it2->second.asString().c_str()); +} + +TEST(TestUrlOptions, GetOptionsString) +{ + const char *ref = "foo=bar&key"; + + CUrlOptions urlOptions(ref); + std::string value = urlOptions.GetOptionsString(); + EXPECT_STREQ(ref, value.c_str()); +} diff --git a/xbmc/utils/test/TestVariant.cpp b/xbmc/utils/test/TestVariant.cpp new file mode 100644 index 0000000..3c96cd0 --- /dev/null +++ b/xbmc/utils/test/TestVariant.cpp @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/Variant.h" + +#include <gtest/gtest.h> + +TEST(TestVariant, VariantTypeInteger) +{ + CVariant a((int)0), b((int64_t)1); + + EXPECT_TRUE(a.isInteger()); + EXPECT_EQ(CVariant::VariantTypeInteger, a.type()); + EXPECT_TRUE(b.isInteger()); + EXPECT_EQ(CVariant::VariantTypeInteger, b.type()); + + EXPECT_EQ((int64_t)1, b.asInteger()); +} + +TEST(TestVariant, VariantTypeUnsignedInteger) +{ + CVariant a((unsigned int)0), b((uint64_t)1); + + EXPECT_TRUE(a.isUnsignedInteger()); + EXPECT_EQ(CVariant::VariantTypeUnsignedInteger, a.type()); + EXPECT_TRUE(b.isUnsignedInteger()); + EXPECT_EQ(CVariant::VariantTypeUnsignedInteger, b.type()); + + EXPECT_EQ((uint64_t)1, b.asUnsignedInteger()); +} + +TEST(TestVariant, VariantTypeBoolean) +{ + CVariant a(true); + + EXPECT_TRUE(a.isBoolean()); + EXPECT_EQ(CVariant::VariantTypeBoolean, a.type()); + + EXPECT_TRUE(a.asBoolean()); +} + +TEST(TestVariant, VariantTypeString) +{ + CVariant a("VariantTypeString"); + CVariant b("VariantTypeString2", sizeof("VariantTypeString2") - 1); + std::string str("VariantTypeString3"); + CVariant c(str); + + EXPECT_TRUE(a.isString()); + EXPECT_EQ(CVariant::VariantTypeString, a.type()); + EXPECT_TRUE(b.isString()); + EXPECT_EQ(CVariant::VariantTypeString, b.type()); + EXPECT_TRUE(c.isString()); + EXPECT_EQ(CVariant::VariantTypeString, c.type()); + + EXPECT_STREQ("VariantTypeString", a.asString().c_str()); + EXPECT_STREQ("VariantTypeString2", b.asString().c_str()); + EXPECT_STREQ("VariantTypeString3", c.asString().c_str()); +} + +TEST(TestVariant, VariantTypeWideString) +{ + CVariant a(L"VariantTypeWideString"); + CVariant b(L"VariantTypeWideString2", sizeof(L"VariantTypeWideString2") - 1); + std::wstring str(L"VariantTypeWideString3"); + CVariant c(str); + + EXPECT_TRUE(a.isWideString()); + EXPECT_EQ(CVariant::VariantTypeWideString, a.type()); + EXPECT_TRUE(b.isWideString()); + EXPECT_EQ(CVariant::VariantTypeWideString, b.type()); + EXPECT_TRUE(c.isWideString()); + EXPECT_EQ(CVariant::VariantTypeWideString, c.type()); + + EXPECT_STREQ(L"VariantTypeWideString", a.asWideString().c_str()); + EXPECT_STREQ(L"VariantTypeWideString2", b.asWideString().c_str()); + EXPECT_STREQ(L"VariantTypeWideString3", c.asWideString().c_str()); +} + +TEST(TestVariant, VariantTypeDouble) +{ + CVariant a((float)0.0f), b((double)0.1f); + + EXPECT_TRUE(a.isDouble()); + EXPECT_EQ(CVariant::VariantTypeDouble, a.type()); + EXPECT_TRUE(b.isDouble()); + EXPECT_EQ(CVariant::VariantTypeDouble, b.type()); + + EXPECT_EQ((float)0.0f, a.asDouble()); + EXPECT_EQ((double)0.1f, b.asDouble()); +} + +TEST(TestVariant, VariantTypeArray) +{ + std::vector<std::string> strarray; + strarray.emplace_back("string1"); + strarray.emplace_back("string2"); + strarray.emplace_back("string3"); + strarray.emplace_back("string4"); + CVariant a(strarray); + + EXPECT_TRUE(a.isArray()); + EXPECT_EQ(CVariant::VariantTypeArray, a.type()); +} + +TEST(TestVariant, VariantTypeObject) +{ + CVariant a; + a["key"] = "value"; + + EXPECT_TRUE(a.isObject()); + EXPECT_EQ(CVariant::VariantTypeObject, a.type()); +} + +TEST(TestVariant, VariantTypeNull) +{ + CVariant a; + + EXPECT_TRUE(a.isNull()); + EXPECT_EQ(CVariant::VariantTypeNull, a.type()); +} + +TEST(TestVariant, VariantFromMap) +{ + std::map<std::string, std::string> strMap; + strMap["key"] = "value"; + CVariant a = strMap; + + EXPECT_TRUE(a.isObject()); + EXPECT_TRUE(a.size() == 1); + EXPECT_EQ(CVariant::VariantTypeObject, a.type()); + EXPECT_TRUE(a.isMember("key")); + EXPECT_TRUE(a["key"].isString()); + EXPECT_STREQ(a["key"].asString().c_str(), "value"); + + std::map<std::string, CVariant> variantMap; + variantMap["key"] = CVariant("value"); + CVariant b = variantMap; + + EXPECT_TRUE(b.isObject()); + EXPECT_TRUE(b.size() == 1); + EXPECT_EQ(CVariant::VariantTypeObject, b.type()); + EXPECT_TRUE(b.isMember("key")); + EXPECT_TRUE(b["key"].isString()); + EXPECT_STREQ(b["key"].asString().c_str(), "value"); +} + +TEST(TestVariant, operatorTest) +{ + std::vector<std::string> strarray; + strarray.emplace_back("string1"); + CVariant a, b, c(strarray), d; + a["key"] = "value"; + b = a; + c[0] = "value2"; + d = c; + + EXPECT_TRUE(a.isObject()); + EXPECT_EQ(CVariant::VariantTypeObject, a.type()); + EXPECT_TRUE(b.isObject()); + EXPECT_EQ(CVariant::VariantTypeObject, b.type()); + EXPECT_TRUE(c.isArray()); + EXPECT_EQ(CVariant::VariantTypeArray, c.type()); + EXPECT_TRUE(d.isArray()); + EXPECT_EQ(CVariant::VariantTypeArray, d.type()); + + EXPECT_TRUE(a == b); + EXPECT_TRUE(c == d); + EXPECT_FALSE(a == d); + + EXPECT_STREQ("value", a["key"].asString().c_str()); + EXPECT_STREQ("value2", c[0].asString().c_str()); +} + +TEST(TestVariant, push_back) +{ + CVariant a, b("variant1"), c("variant2"), d("variant3"); + a.push_back(b); + a.push_back(c); + a.push_back(d); + + EXPECT_TRUE(a.isArray()); + EXPECT_EQ(CVariant::VariantTypeArray, a.type()); + EXPECT_STREQ("variant1", a[0].asString().c_str()); + EXPECT_STREQ("variant2", a[1].asString().c_str()); + EXPECT_STREQ("variant3", a[2].asString().c_str()); +} + +TEST(TestVariant, append) +{ + CVariant a, b("variant1"), c("variant2"), d("variant3"); + a.append(b); + a.append(c); + a.append(d); + + EXPECT_TRUE(a.isArray()); + EXPECT_EQ(CVariant::VariantTypeArray, a.type()); + EXPECT_STREQ("variant1", a[0].asString().c_str()); + EXPECT_STREQ("variant2", a[1].asString().c_str()); + EXPECT_STREQ("variant3", a[2].asString().c_str()); +} + +TEST(TestVariant, c_str) +{ + CVariant a("variant"); + + EXPECT_STREQ("variant", a.c_str()); +} + +TEST(TestVariant, swap) +{ + CVariant a((int)0), b("variant"); + + EXPECT_TRUE(a.isInteger()); + EXPECT_TRUE(b.isString()); + + a.swap(b); + EXPECT_TRUE(b.isInteger()); + EXPECT_TRUE(a.isString()); +} + +TEST(TestVariant, iterator_array) +{ + std::vector<std::string> strarray; + strarray.emplace_back("string"); + strarray.emplace_back("string"); + strarray.emplace_back("string"); + strarray.emplace_back("string"); + CVariant a(strarray); + + EXPECT_TRUE(a.isArray()); + EXPECT_EQ(CVariant::VariantTypeArray, a.type()); + + for (auto it = a.begin_array(); it != a.end_array(); it++) + { + EXPECT_STREQ("string", it->c_str()); + } + + for (auto const_it = a.begin_array(); const_it != a.end_array(); const_it++) + { + EXPECT_STREQ("string", const_it->c_str()); + } +} + +TEST(TestVariant, iterator_map) +{ + CVariant a; + a["key1"] = "string"; + a["key2"] = "string"; + a["key3"] = "string"; + a["key4"] = "string"; + + EXPECT_TRUE(a.isObject()); + EXPECT_EQ(CVariant::VariantTypeObject, a.type()); + + for (auto it = a.begin_map(); it != a.end_map(); it++) + { + EXPECT_STREQ("string", it->second.c_str()); + } + + for (auto const_it = a.begin_map(); const_it != a.end_map(); const_it++) + { + EXPECT_STREQ("string", const_it->second.c_str()); + } +} + +TEST(TestVariant, size) +{ + std::vector<std::string> strarray; + strarray.emplace_back("string"); + strarray.emplace_back("string"); + strarray.emplace_back("string"); + strarray.emplace_back("string"); + CVariant a(strarray); + + EXPECT_EQ((unsigned int)4, a.size()); +} + +TEST(TestVariant, empty) +{ + std::vector<std::string> strarray; + CVariant a(strarray); + + EXPECT_TRUE(a.empty()); +} + +TEST(TestVariant, clear) +{ + std::vector<std::string> strarray; + strarray.emplace_back("string"); + strarray.emplace_back("string"); + strarray.emplace_back("string"); + strarray.emplace_back("string"); + CVariant a(strarray); + + EXPECT_FALSE(a.empty()); + a.clear(); + EXPECT_TRUE(a.empty()); +} + +TEST(TestVariant, erase) +{ + std::vector<std::string> strarray; + strarray.emplace_back("string1"); + strarray.emplace_back("string2"); + strarray.emplace_back("string3"); + strarray.emplace_back("string4"); + CVariant a, b(strarray); + a["key1"] = "string1"; + a["key2"] = "string2"; + a["key3"] = "string3"; + a["key4"] = "string4"; + + EXPECT_STREQ("string2", a["key2"].c_str()); + EXPECT_STREQ("string2", b[1].c_str()); + a.erase("key2"); + b.erase(1); + EXPECT_FALSE(a["key2"].c_str()); + EXPECT_STREQ("string3", b[1].c_str()); +} + +TEST(TestVariant, isMember) +{ + CVariant a; + a["key1"] = "string1"; + + EXPECT_TRUE(a.isMember("key1")); + EXPECT_FALSE(a.isMember("key2")); +} diff --git a/xbmc/utils/test/TestXBMCTinyXML.cpp b/xbmc/utils/test/TestXBMCTinyXML.cpp new file mode 100644 index 0000000..b3f84eb --- /dev/null +++ b/xbmc/utils/test/TestXBMCTinyXML.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "test/TestUtils.h" +#include "utils/StringUtils.h" +#include "utils/XBMCTinyXML.h" + +#include <gtest/gtest.h> + +TEST(TestXBMCTinyXML, ParseFromString) +{ + bool retval = false; + // scraper results with unescaped & + CXBMCTinyXML doc; + std::string data("<details><url function=\"ParseTMDBRating\" " + "cache=\"tmdb-en-12244.json\">" + "http://api.themoviedb.org/3/movie/12244" + "?api_key=57983e31fb435df4df77afb854740ea9" + "&language=en???</url></details>"); + doc.Parse(data); + TiXmlNode *root = doc.RootElement(); + if (root && root->ValueStr() == "details") + { + TiXmlElement *url = root->FirstChildElement("url"); + if (url && url->FirstChild()) + { + retval = (url->FirstChild()->ValueStr() == "http://api.themoviedb.org/3/movie/12244?api_key=57983e31fb435df4df77afb854740ea9&language=en???"); + } + } + EXPECT_TRUE(retval); +} + +TEST(TestXBMCTinyXML, ParseFromFileHandle) +{ + bool retval = false; + // scraper results with unescaped & + CXBMCTinyXML doc; + FILE *f = fopen(XBMC_REF_FILE_PATH("/xbmc/utils/test/CXBMCTinyXML-test.xml").c_str(), "r"); + ASSERT_NE(nullptr, f); + doc.LoadFile(f); + fclose(f); + TiXmlNode *root = doc.RootElement(); + if (root && root->ValueStr() == "details") + { + TiXmlElement *url = root->FirstChildElement("url"); + if (url && url->FirstChild()) + { + std::string str = url->FirstChild()->ValueStr(); + retval = (StringUtils::Trim(str) == "http://api.themoviedb.org/3/movie/12244?api_key=57983e31fb435df4df77afb854740ea9&language=en???"); + } + } + EXPECT_TRUE(retval); +} diff --git a/xbmc/utils/test/TestXMLUtils.cpp b/xbmc/utils/test/TestXMLUtils.cpp new file mode 100644 index 0000000..ba4c87c --- /dev/null +++ b/xbmc/utils/test/TestXMLUtils.cpp @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "XBDateTime.h" +#include "utils/StringUtils.h" +#include "utils/XMLUtils.h" + +#include <gtest/gtest.h> + +TEST(TestXMLUtils, GetHex) +{ + CXBMCTinyXML a; + uint32_t ref, val; + + a.Parse(std::string("<root><node>0xFF</node></root>")); + EXPECT_TRUE(XMLUtils::GetHex(a.RootElement(), "node", val)); + + ref = 0xFF; + EXPECT_EQ(ref, val); +} + +TEST(TestXMLUtils, GetUInt) +{ + CXBMCTinyXML a; + uint32_t ref, val; + + a.Parse(std::string("<root><node>1000</node></root>")); + EXPECT_TRUE(XMLUtils::GetUInt(a.RootElement(), "node", val)); + + ref = 1000; + EXPECT_EQ(ref, val); +} + +TEST(TestXMLUtils, GetLong) +{ + CXBMCTinyXML a; + long ref, val; + + a.Parse(std::string("<root><node>1000</node></root>")); + EXPECT_TRUE(XMLUtils::GetLong(a.RootElement(), "node", val)); + + ref = 1000; + EXPECT_EQ(ref, val); +} + +TEST(TestXMLUtils, GetFloat) +{ + CXBMCTinyXML a; + float ref, val; + + a.Parse(std::string("<root><node>1000.1f</node></root>")); + EXPECT_TRUE(XMLUtils::GetFloat(a.RootElement(), "node", val)); + EXPECT_TRUE(XMLUtils::GetFloat(a.RootElement(), "node", val, 1000.0f, + 1000.2f)); + ref = 1000.1f; + EXPECT_EQ(ref, val); +} + +TEST(TestXMLUtils, GetDouble) +{ + CXBMCTinyXML a; + double val; + std::string refstr, valstr; + + a.Parse(std::string("<root><node>1000.1f</node></root>")); + EXPECT_TRUE(XMLUtils::GetDouble(a.RootElement(), "node", val)); + + refstr = "1000.100000"; + valstr = StringUtils::Format("{:f}", val); + EXPECT_STREQ(refstr.c_str(), valstr.c_str()); +} + +TEST(TestXMLUtils, GetInt) +{ + CXBMCTinyXML a; + int ref, val; + + a.Parse(std::string("<root><node>1000</node></root>")); + EXPECT_TRUE(XMLUtils::GetInt(a.RootElement(), "node", val)); + EXPECT_TRUE(XMLUtils::GetInt(a.RootElement(), "node", val, 999, 1001)); + + ref = 1000; + EXPECT_EQ(ref, val); +} + +TEST(TestXMLUtils, GetBoolean) +{ + CXBMCTinyXML a; + bool ref, val; + + a.Parse(std::string("<root><node>true</node></root>")); + EXPECT_TRUE(XMLUtils::GetBoolean(a.RootElement(), "node", val)); + + ref = true; + EXPECT_EQ(ref, val); +} + +TEST(TestXMLUtils, GetString) +{ + CXBMCTinyXML a; + std::string ref, val; + + a.Parse(std::string("<root><node>some string</node></root>")); + EXPECT_TRUE(XMLUtils::GetString(a.RootElement(), "node", val)); + + ref = "some string"; + EXPECT_STREQ(ref.c_str(), val.c_str()); +} + +TEST(TestXMLUtils, GetAdditiveString) +{ + CXBMCTinyXML a, b; + std::string ref, val; + + a.Parse(std::string("<root>\n" + " <node>some string1</node>\n" + " <node>some string2</node>\n" + " <node>some string3</node>\n" + " <node>some string4</node>\n" + " <node>some string5</node>\n" + "</root>\n")); + EXPECT_TRUE(XMLUtils::GetAdditiveString(a.RootElement(), "node", ",", val)); + + ref = "some string1,some string2,some string3,some string4,some string5"; + EXPECT_STREQ(ref.c_str(), val.c_str()); + + val.clear(); + b.Parse(std::string("<root>\n" + " <node>some string1</node>\n" + " <node>some string2</node>\n" + " <node clear=\"true\">some string3</node>\n" + " <node>some string4</node>\n" + " <node>some string5</node>\n" + "</root>\n")); + EXPECT_TRUE(XMLUtils::GetAdditiveString(b.RootElement(), "node", ",", val)); + + ref = "some string3,some string4,some string5"; + EXPECT_STREQ(ref.c_str(), val.c_str()); +} + +TEST(TestXMLUtils, GetStringArray) +{ + CXBMCTinyXML a; + std::vector<std::string> strarray; + + a.Parse(std::string("<root>\n" + " <node>some string1</node>\n" + " <node>some string2</node>\n" + " <node>some string3</node>\n" + " <node>some string4</node>\n" + " <node>some string5</node>\n" + "</root>\n")); + EXPECT_TRUE(XMLUtils::GetStringArray(a.RootElement(), "node", strarray)); + + EXPECT_STREQ("some string1", strarray.at(0).c_str()); + EXPECT_STREQ("some string2", strarray.at(1).c_str()); + EXPECT_STREQ("some string3", strarray.at(2).c_str()); + EXPECT_STREQ("some string4", strarray.at(3).c_str()); + EXPECT_STREQ("some string5", strarray.at(4).c_str()); +} + +TEST(TestXMLUtils, GetPath) +{ + CXBMCTinyXML a, b; + std::string ref, val; + + a.Parse(std::string("<root><node urlencoded=\"yes\">special://xbmc/</node></root>")); + EXPECT_TRUE(XMLUtils::GetPath(a.RootElement(), "node", val)); + + ref = "special://xbmc/"; + EXPECT_STREQ(ref.c_str(), val.c_str()); + + val.clear(); + b.Parse(std::string("<root><node>special://xbmcbin/</node></root>")); + EXPECT_TRUE(XMLUtils::GetPath(b.RootElement(), "node", val)); + + ref = "special://xbmcbin/"; + EXPECT_STREQ(ref.c_str(), val.c_str()); +} + +TEST(TestXMLUtils, GetDate) +{ + CXBMCTinyXML a; + CDateTime ref, val; + + a.Parse(std::string("<root><node>2012-07-08</node></root>")); + EXPECT_TRUE(XMLUtils::GetDate(a.RootElement(), "node", val)); + ref.SetDate(2012, 7, 8); + EXPECT_TRUE(ref == val); +} + +TEST(TestXMLUtils, GetDateTime) +{ + CXBMCTinyXML a; + CDateTime ref, val; + + a.Parse(std::string("<root><node>2012-07-08 01:02:03</node></root>")); + EXPECT_TRUE(XMLUtils::GetDateTime(a.RootElement(), "node", val)); + ref.SetDateTime(2012, 7, 8, 1, 2, 3); + EXPECT_TRUE(ref == val); +} + +TEST(TestXMLUtils, SetString) +{ + CXBMCTinyXML a; + std::string ref, val; + + a.Parse(std::string("<root></root>")); + XMLUtils::SetString(a.RootElement(), "node", "some string"); + EXPECT_TRUE(XMLUtils::GetString(a.RootElement(), "node", val)); + + ref = "some string"; + EXPECT_STREQ(ref.c_str(), val.c_str()); +} + +TEST(TestXMLUtils, SetAdditiveString) +{ + CXBMCTinyXML a; + std::string ref, val; + + a.Parse(std::string("<root></root>")); + XMLUtils::SetAdditiveString(a.RootElement(), "node", ",", + "some string1,some string2,some string3,some string4,some string5"); + EXPECT_TRUE(XMLUtils::GetAdditiveString(a.RootElement(), "node", ",", val)); + + ref = "some string1,some string2,some string3,some string4,some string5"; + EXPECT_STREQ(ref.c_str(), val.c_str()); +} + +TEST(TestXMLUtils, SetStringArray) +{ + CXBMCTinyXML a; + std::vector<std::string> strarray; + strarray.emplace_back("some string1"); + strarray.emplace_back("some string2"); + strarray.emplace_back("some string3"); + strarray.emplace_back("some string4"); + strarray.emplace_back("some string5"); + + a.Parse(std::string("<root></root>")); + XMLUtils::SetStringArray(a.RootElement(), "node", strarray); + EXPECT_TRUE(XMLUtils::GetStringArray(a.RootElement(), "node", strarray)); + + EXPECT_STREQ("some string1", strarray.at(0).c_str()); + EXPECT_STREQ("some string2", strarray.at(1).c_str()); + EXPECT_STREQ("some string3", strarray.at(2).c_str()); + EXPECT_STREQ("some string4", strarray.at(3).c_str()); + EXPECT_STREQ("some string5", strarray.at(4).c_str()); +} + +TEST(TestXMLUtils, SetInt) +{ + CXBMCTinyXML a; + int ref, val; + + a.Parse(std::string("<root></root>")); + XMLUtils::SetInt(a.RootElement(), "node", 1000); + EXPECT_TRUE(XMLUtils::GetInt(a.RootElement(), "node", val)); + + ref = 1000; + EXPECT_EQ(ref, val); +} + +TEST(TestXMLUtils, SetFloat) +{ + CXBMCTinyXML a; + float ref, val; + + a.Parse(std::string("<root></root>")); + XMLUtils::SetFloat(a.RootElement(), "node", 1000.1f); + EXPECT_TRUE(XMLUtils::GetFloat(a.RootElement(), "node", val)); + + ref = 1000.1f; + EXPECT_EQ(ref, val); +} + +TEST(TestXMLUtils, SetBoolean) +{ + CXBMCTinyXML a; + bool ref, val; + + a.Parse(std::string("<root></root>")); + XMLUtils::SetBoolean(a.RootElement(), "node", true); + EXPECT_TRUE(XMLUtils::GetBoolean(a.RootElement(), "node", val)); + + ref = true; + EXPECT_EQ(ref, val); +} + +TEST(TestXMLUtils, SetHex) +{ + CXBMCTinyXML a; + uint32_t ref, val; + + a.Parse(std::string("<root></root>")); + XMLUtils::SetHex(a.RootElement(), "node", 0xFF); + EXPECT_TRUE(XMLUtils::GetHex(a.RootElement(), "node", val)); + + ref = 0xFF; + EXPECT_EQ(ref, val); +} + +TEST(TestXMLUtils, SetPath) +{ + CXBMCTinyXML a; + std::string ref, val; + + a.Parse(std::string("<root></root>")); + XMLUtils::SetPath(a.RootElement(), "node", "special://xbmc/"); + EXPECT_TRUE(XMLUtils::GetPath(a.RootElement(), "node", val)); + + ref = "special://xbmc/"; + EXPECT_STREQ(ref.c_str(), val.c_str()); +} + +TEST(TestXMLUtils, SetLong) +{ + CXBMCTinyXML a; + long ref, val; + + a.Parse(std::string("<root></root>")); + XMLUtils::SetLong(a.RootElement(), "node", 1000); + EXPECT_TRUE(XMLUtils::GetLong(a.RootElement(), "node", val)); + + ref = 1000; + EXPECT_EQ(ref, val); +} + +TEST(TestXMLUtils, SetDate) +{ + CXBMCTinyXML a; + CDateTime ref, val; + + a.Parse(std::string("<root></root>")); + ref.SetDate(2012, 7, 8); + XMLUtils::SetDate(a.RootElement(), "node", ref); + EXPECT_TRUE(XMLUtils::GetDate(a.RootElement(), "node", val)); + EXPECT_TRUE(ref == val); +} + +TEST(TestXMLUtils, SetDateTime) +{ + CXBMCTinyXML a; + CDateTime ref, val; + + a.Parse(std::string("<root></root>")); + ref.SetDateTime(2012, 7, 8, 1, 2, 3); + XMLUtils::SetDateTime(a.RootElement(), "node", ref); + EXPECT_TRUE(XMLUtils::GetDateTime(a.RootElement(), "node", val)); + EXPECT_TRUE(ref == val); +} diff --git a/xbmc/utils/test/Testlog.cpp b/xbmc/utils/test/Testlog.cpp new file mode 100644 index 0000000..a700d2a --- /dev/null +++ b/xbmc/utils/test/Testlog.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "CompileInfo.h" +#include "ServiceBroker.h" +#include "filesystem/File.h" +#include "filesystem/SpecialProtocol.h" +#include "test/TestUtils.h" +#include "utils/RegExp.h" +#include "utils/StringUtils.h" +#include "utils/log.h" + +#include <stdlib.h> + +#include <gtest/gtest.h> + +class Testlog : public testing::Test +{ +protected: + Testlog() = default; + ~Testlog() override { CServiceBroker::GetLogging().Deinitialize(); } +}; + +TEST_F(Testlog, Log) +{ + std::string logfile, logstring; + char buf[100]; + ssize_t bytesread; + XFILE::CFile file; + CRegExp regex; + + std::string appName = CCompileInfo::GetAppName(); + StringUtils::ToLower(appName); + logfile = CSpecialProtocol::TranslatePath("special://temp/") + appName + ".log"; + CServiceBroker::GetLogging().Initialize( + CSpecialProtocol::TranslatePath("special://temp/").c_str()); + EXPECT_TRUE(XFILE::CFile::Exists(logfile)); + + CLog::Log(LOGDEBUG, "debug log message"); + CLog::Log(LOGINFO, "info log message"); + CLog::Log(LOGWARNING, "warning log message"); + CLog::Log(LOGERROR, "error log message"); + CLog::Log(LOGFATAL, "fatal log message"); + CLog::Log(LOGNONE, "none type log message"); + CServiceBroker::GetLogging().Deinitialize(); + + EXPECT_TRUE(file.Open(logfile)); + while ((bytesread = file.Read(buf, sizeof(buf) - 1)) > 0) + { + buf[bytesread] = '\0'; + logstring.append(buf); + } + file.Close(); + EXPECT_FALSE(logstring.empty()); + + EXPECT_STREQ("\xEF\xBB\xBF", logstring.substr(0, 3).c_str()); + + EXPECT_TRUE(regex.RegComp(".*(debug|DEBUG) <general>: debug log message.*")); + EXPECT_GE(regex.RegFind(logstring), 0); + EXPECT_TRUE(regex.RegComp(".*(info|INFO) <general>: info log message.*")); + EXPECT_GE(regex.RegFind(logstring), 0); + EXPECT_TRUE(regex.RegComp(".*(warning|WARNING) <general>: warning log message.*")); + EXPECT_GE(regex.RegFind(logstring), 0); + EXPECT_TRUE(regex.RegComp(".*(error|ERROR) <general>: error log message.*")); + EXPECT_GE(regex.RegFind(logstring), 0); + EXPECT_TRUE(regex.RegComp(".*(critical|CRITICAL|fatal|FATAL) <general>: fatal log message.*")); + EXPECT_GE(regex.RegFind(logstring), 0); + EXPECT_TRUE(regex.RegComp(".*(off|OFF) <general>: none type log message.*")); + EXPECT_GE(regex.RegFind(logstring), 0); + + EXPECT_TRUE(XFILE::CFile::Delete(logfile)); +} + +TEST_F(Testlog, SetLogLevel) +{ + std::string logfile; + + std::string appName = CCompileInfo::GetAppName(); + StringUtils::ToLower(appName); + logfile = CSpecialProtocol::TranslatePath("special://temp/") + appName + ".log"; + CServiceBroker::GetLogging().Initialize( + CSpecialProtocol::TranslatePath("special://temp/").c_str()); + EXPECT_TRUE(XFILE::CFile::Exists(logfile)); + + EXPECT_EQ(LOG_LEVEL_DEBUG, CServiceBroker::GetLogging().GetLogLevel()); + CServiceBroker::GetLogging().SetLogLevel(LOG_LEVEL_MAX); + EXPECT_EQ(LOG_LEVEL_MAX, CServiceBroker::GetLogging().GetLogLevel()); + + CServiceBroker::GetLogging().Deinitialize(); + EXPECT_TRUE(XFILE::CFile::Delete(logfile)); +} diff --git a/xbmc/utils/test/Testrfft.cpp b/xbmc/utils/test/Testrfft.cpp new file mode 100644 index 0000000..a6c859d --- /dev/null +++ b/xbmc/utils/test/Testrfft.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2015-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#include "utils/rfft.h" + +#include <gtest/gtest.h> + +#if defined(TARGET_WINDOWS) && !defined(_USE_MATH_DEFINES) +#define _USE_MATH_DEFINES +#endif + +#include <math.h> + + +TEST(TestRFFT, SimpleSignal) +{ + const int size = 32; + const int freq1 = 5; + const int freq2[] = {1,7}; + std::vector<float> input(2*size); + std::vector<float> output(size); + for (size_t i=0;i<size;++i) + { + input[2*i] = cos(freq1*2.0*M_PI*i/size); + input[2*i+1] = cos(freq2[0]*2.0*M_PI*i/size)+cos(freq2[1]*2.0*M_PI*i/size); + } + RFFT transform(size, false); + + transform.calc(&input[0], &output[0]); + + for (int i=0;i<size/2;++i) + { + EXPECT_NEAR(output[2*i],(i==freq1?1.0:0.0), 1e-7); + EXPECT_NEAR(output[2*i+1], ((i==freq2[0]||i==freq2[1])?1.0:0.0), 1e-7); + } +} diff --git a/xbmc/utils/test/data/language/Spanish/strings.po b/xbmc/utils/test/data/language/Spanish/strings.po new file mode 100644 index 0000000..8ee8d02 --- /dev/null +++ b/xbmc/utils/test/data/language/Spanish/strings.po @@ -0,0 +1,26 @@ +# Kodi Media Center language file +msgid "" +msgstr "" +"Project-Id-Version: XBMC Main\n" +"Report-Msgid-Bugs-To: http://trac.xbmc.org/\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Kodi Translation Team\n" +"Language-Team: Spanish (http://www.transifex.com/projects/p/xbmc-main/language/es/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: es\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgctxt "#0" +msgid "Programs" +msgstr "Programas" + +msgctxt "#1" +msgid "Pictures" +msgstr "Imágenes" + +msgctxt "#2" +msgid "Music" +msgstr "Música" |