test/config/test_configmanager.cc
Rama master · réplica de lectura del repositorio original.
/*GRB*
Gerbera - https://gerbera.io/
test_configmanager.cc - this file is part of Gerbera.
Copyright (C) 2016-2026 Gerbera Contributors
Gerbera is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
Gerbera is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Gerbera. If not, see <http://www.gnu.org/licenses/>.
$Id$
*/
#include "config/config_definition.h"
#include "config/config_generator.h"
#include "config/config_manager.h"
#include "config/config_val.h"
#include "exceptions.h"
#include "util/tools.h"
#include <array>
#include <fstream>
#include <gtest/gtest.h>
#include <memory>
#include <pugixml.hpp>
#include <string>
#include <utility>
#include <vector>
class ConfigManagerTest : public ::testing::Test {
public:
ConfigManagerTest() = default;
~ConfigManagerTest() override = default;
void SetUp() override
{
definition = std::make_shared<ConfigDefinition>();
definition->init(definition);
gerberaDir = createTempPath();
fs::path grbWeb = gerberaDir / "web";
createDirectory(grbWeb);
fs::path grbJs = gerberaDir / "js";
createDirectory(grbJs);
fs::path configDir = gerberaDir / ".config";
createDirectory(configDir);
// Create mock files, allowing for .init()
auto mockFiles = std::array {
grbJs / "common.js",
grbJs / "import.js",
grbJs / "playlists.js",
grbJs / "metadata.js",
gerberaDir / "sqlite3.sql",
gerberaDir / "sqlite3-drop.sql",
gerberaDir / "sqlite3-upgrade.xml",
gerberaDir / "mysql.sql",
gerberaDir / "mysql-drop.sql",
gerberaDir / "mysql-upgrade.xml",
gerberaDir / "postgres.sql",
gerberaDir / "postgres-drop.sql",
gerberaDir / "postgres-upgrade.xml",
};
std::ofstream file;
for (auto&& mFile : mockFiles) {
file.open(mFile);
file.close();
}
configFile = configDir / "config.xml";
home = gerberaDir;
prefix = gerberaDir;
magic = "";
confdir = ".config";
// Create config using generator
std::string cfgContent = createConfig();
file.open(configDir / "config.xml");
file << cfgContent;
file.close();
subject = nullptr;
}
static fs::path createTempPath()
{
fs::path ss = fs::path(CMAKE_BINARY_DIR) / "test" / "config" / generateRandomId();
createDirectory(ss);
return ss;
}
static void createDirectory(const fs::path& dir)
{
if (mkdir(dir.c_str(), 0777) < 0) {
throw_std_runtime_error("Failed to create test_config temporary directory for testing: {}", dir.c_str());
}
}
std::string createConfig() const
{
ConfigGenerator configGenerator(definition, GERBERA_TEST, ConfigLevel::Base);
return configGenerator.generate(home, confdir, prefix, magic);
}
void TearDown() override
{
delete subject;
fs::remove_all(gerberaDir);
}
fs::path gerberaDir;
fs::path configFile;
fs::path home;
fs::path confdir;
fs::path prefix;
fs::path magic;
ConfigManager* subject;
std::shared_ptr<ConfigDefinition> definition;
};
TEST_F(ConfigManagerTest, LoadsWebUIDefaultValues)
{
auto shared = std::make_shared<ConfigManager>(definition, configFile, home, confdir, prefix, false);
shared->load(home, "");
ASSERT_TRUE(shared->getBoolOption(ConfigVal::SERVER_UI_ENABLED));
ASSERT_TRUE(shared->getBoolOption(ConfigVal::SERVER_UI_SHOW_TOOLTIPS));
ASSERT_FALSE(shared->getBoolOption(ConfigVal::SERVER_UI_ACCOUNTS_ENABLED));
ASSERT_EQ(30, shared->getLongOption(ConfigVal::SERVER_UI_SESSION_TIMEOUT));
}
TEST_F(ConfigManagerTest, ThrowsExceptionWhenMissingConfigFileAndNoDefault)
{
std::ostringstream expErrMsg;
fs::path notExistsDir = home / "not_exists";
fs::path configFile = fs::weakly_canonical(notExistsDir / confdir / "config.xml");
expErrMsg << "\nThe server configuration file could not be found: ";
expErrMsg << configFile.string() << "\n";
expErrMsg << "Gerbera could not find a default configuration file.\n";
expErrMsg << "Try specifying an alternative configuration file on the command line.\n";
expErrMsg << "For a list of options run: gerbera -h\n";
configFile = "";
try {
auto shared = std::make_shared<ConfigManager>(definition, configFile, notExistsDir, confdir, prefix, false);
shared->load(notExistsDir, "");
} catch (const std::runtime_error& err) {
EXPECT_EQ(err.what(), expErrMsg.str());
}
}
TEST_F(ConfigManagerTest, LoadsConfigFromDefaultHomeWhenExistsButNotSpecified)
{
configFile = "";
auto shared = std::make_shared<ConfigManager>(definition, configFile, home, confdir, prefix, false);
shared->load(home, "");
ASSERT_TRUE(shared->getBoolOption(ConfigVal::SERVER_UI_ENABLED));
ASSERT_TRUE(shared->getBoolOption(ConfigVal::SERVER_UI_SHOW_TOOLTIPS));
ASSERT_FALSE(shared->getBoolOption(ConfigVal::SERVER_UI_ACCOUNTS_ENABLED));
ASSERT_EQ(30, shared->getLongOption(ConfigVal::SERVER_UI_SESSION_TIMEOUT));
}
#ifdef HAVE_JS
TEST_F(ConfigManagerTest, LoadsAudioTitleFormatFromScriptOptions)
{
pugi::xml_document document;
ASSERT_TRUE(document.load_file(configFile.c_str()));
auto layout = document.child("config").child("import").child("scripting").child("virtual-layout");
ASSERT_TRUE(layout);
auto scriptOptions = layout.child("script-options");
if (!scriptOptions)
scriptOptions = layout.append_child("script-options");
auto option = scriptOptions.append_child("script-option");
option.append_attribute("name") = "audioTitleFormat";
option.append_attribute("value") = "%tracknr2% - %title%";
ASSERT_TRUE(document.save_file(configFile.c_str()));
auto shared = std::make_shared<ConfigManager>(definition, configFile, home, confdir, prefix, false);
shared->load(home, "");
const auto options = shared->getDictionaryOption(ConfigVal::IMPORT_SCRIPTING_IMPORT_SCRIPT_OPTIONS);
EXPECT_EQ(options.at("audioTitleFormat"), "%tracknr2% - %title%");
}
#endif
TEST_F(ConfigManagerTest, LoadsAlbumFormatAndIndependentReplacementsForBothLayoutEngines)
{
pugi::xml_document document;
ASSERT_TRUE(document.load_file(configFile.c_str()));
auto layout = document.child("config").child("import").child("scripting").child("virtual-layout");
ASSERT_TRUE(layout);
layout.attribute("type") = "builtin";
auto options = layout.child("script-options");
if (!options)
options = layout.append_child("script-options");
auto option = options.append_child("script-option");
option.append_attribute("name") = "albumTitleFormat";
option.append_attribute("value") = "%albumartist% - %albumtitle% (%year%)";
auto rule = layout.append_child("album-title-replacements").append_child("replace");
rule.append_attribute("from") = "_";
rule.append_attribute("to") = " ";
rule.append_attribute("if-albumartist") = "Various Artists";
ASSERT_TRUE(document.save_file(configFile.c_str()));
auto shared = std::make_shared<ConfigManager>(definition, configFile, home, confdir, prefix, false);
shared->load(home, "");
EXPECT_EQ(shared->getDictionaryOption(ConfigVal::IMPORT_SCRIPTING_IMPORT_SCRIPT_OPTIONS).at("albumTitleFormat"), "%albumartist% - %albumtitle% (%year%)");
const auto rules = shared->getVectorOption(ConfigVal::IMPORT_SCRIPTING_ALBUM_TITLE_REPLACEMENTS);
const std::vector<std::pair<std::string, std::string>> expected { { "from", "_" }, { "to", " " }, { "if-albumartist", "Various Artists" } };
ASSERT_EQ(rules.size(), 1U);
EXPECT_EQ(rules[0], expected);
EXPECT_TRUE(shared->getVectorOption(ConfigVal::IMPORT_SCRIPTING_AUDIO_TITLE_REPLACEMENTS).empty());
}
TEST_F(ConfigManagerTest, LoadsOrderedAudioTitleReplacements)
{
pugi::xml_document document;
ASSERT_TRUE(document.load_file(configFile.c_str()));
auto layout = document.child("config").child("import").child("scripting").child("virtual-layout");
ASSERT_TRUE(layout);
auto rules = layout.append_child("title-replacements");
auto first = rules.append_child("replace");
first.append_attribute("from") = "_";
first.append_attribute("to") = " ";
auto second = rules.append_child("replace");
second.append_attribute("from") = "REMOVE";
second.append_attribute("to") = "";
second.append_attribute("regex") = "yes";
second.append_attribute("if-albumtitle") = "Album";
second.append_attribute("if-artist") = "Artist";
ASSERT_TRUE(document.save_file(configFile.c_str()));
auto shared = std::make_shared<ConfigManager>(definition, configFile, home, confdir, prefix, false);
shared->load(home, "");
const auto entries = shared->getVectorOption(ConfigVal::IMPORT_SCRIPTING_AUDIO_TITLE_REPLACEMENTS);
ASSERT_EQ(entries.size(), 2);
const std::vector<std::pair<std::string, std::string>> expectedFirst { { "from", "_" }, { "to", " " } };
const std::vector<std::pair<std::string, std::string>> expectedSecond { { "from", "REMOVE" }, { "regex", "yes" }, { "if-albumtitle", "Album" }, { "if-artist", "Artist" } };
EXPECT_EQ(entries[0], expectedFirst);
EXPECT_EQ(entries[1], expectedSecond);
}