changeset 240:f6d9fdb5eeeb

Xdg: don't use bad directories, add tests
author David Demelier <markand@malikania.fr>
date Thu, 14 Aug 2014 09:56:25 +0200
parents 9b69f810d3b9
children d9409b338f2f
files C++/Tests/OptionParser/main.cpp C++/Tests/Xdg/CMakeLists.txt C++/Tests/Xdg/main.cpp C++/Xdg.cpp C++/Xdg.h CMakeLists.txt
diffstat 6 files changed, 406 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/C++/Tests/OptionParser/main.cpp	Tue Aug 12 16:45:33 2014 +0200
+++ b/C++/Tests/OptionParser/main.cpp	Thu Aug 14 09:56:25 2014 +0200
@@ -1,3 +1,21 @@
+/*
+ * main.cpp -- main test file for OptionParser
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
 #include <gtest/gtest.h>
 
 #include <OptionParser.h>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/Tests/Xdg/CMakeLists.txt	Thu Aug 14 09:56:25 2014 +0200
@@ -0,0 +1,26 @@
+#
+# CMakeLists.txt -- tests for XDG
+#
+# Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+#
+
+set(
+	SOURCES
+	${code_SOURCE_DIR}/C++/Xdg.cpp
+	${code_SOURCE_DIR}/C++/Xdg.h
+	main.cpp
+)
+
+define_test(xdg "${SOURCES}")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C++/Tests/Xdg/main.cpp	Thu Aug 14 09:56:25 2014 +0200
@@ -0,0 +1,340 @@
+/*
+ * main.cpp -- main test file for XDG
+ *
+ * Copyright (c) 2013, 2014 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <gtest/gtest.h>
+
+#include <Xdg.h>
+
+using namespace testing;
+
+namespace {
+
+std::string myhome;
+
+}
+
+TEST(HomeEmpty, config)
+{
+	ASSERT_TRUE(unsetenv("XDG_CONFIG_HOME") == 0);
+
+	try {
+		Xdg xdg;
+
+		ASSERT_EQ(myhome + "/.config", xdg.configHome());
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(HomeEmpty, data)
+{
+	ASSERT_TRUE(unsetenv("XDG_DATA_HOME") == 0);
+
+	try {
+		Xdg xdg;
+
+		ASSERT_EQ(myhome + "/.local/share", xdg.dataHome());
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(HomeEmpty, cache)
+{
+	ASSERT_TRUE(unsetenv("XDG_CACHE_HOME") == 0);
+
+	try {
+		Xdg xdg;
+
+		ASSERT_EQ(myhome + "/.cache", xdg.cacheHome());
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(HomeEmpty, runtime)
+{
+	ASSERT_TRUE(unsetenv("XDG_RUNTIME_DIR") == 0);
+
+	try {
+		Xdg xdg;
+
+		try {
+			xdg.runtimeDir();
+
+			ASSERT_TRUE(false);
+		} catch (const std::exception &) { }
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(HomeValid, config)
+{
+	ASSERT_TRUE(setenv("XDG_CONFIG_HOME", "/test/config", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		ASSERT_EQ("/test/config", xdg.configHome());
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(HomeValid, data)
+{
+	ASSERT_TRUE(setenv("XDG_DATA_HOME", "/test/data", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		ASSERT_EQ("/test/data", xdg.dataHome());
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(HomeValid, cache)
+{
+	ASSERT_TRUE(setenv("XDG_CACHE_HOME", "/test/cache", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		ASSERT_EQ("/test/cache", xdg.cacheHome());
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(HomeValid, runtime)
+{
+	ASSERT_TRUE(setenv("XDG_RUNTIME_DIR", "/test/runtime", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		ASSERT_EQ("/test/runtime", xdg.runtimeDir());
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(HomeInvalid, config)
+{
+	ASSERT_TRUE(setenv("XDG_CONFIG_HOME", "invalid", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		ASSERT_EQ(myhome + "/.config", xdg.configHome());
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(HomeInvalid, data)
+{
+	ASSERT_TRUE(setenv("XDG_DATA_HOME", "invalid", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		ASSERT_EQ(myhome + "/.local/share", xdg.dataHome());
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(HomeInvalid, cache)
+{
+	ASSERT_TRUE(setenv("XDG_CACHE_HOME", "invalid", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		ASSERT_EQ(myhome + "/.cache", xdg.cacheHome());
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(HomeInvalid, runtime)
+{
+	ASSERT_TRUE(setenv("XDG_RUNTIME_DIR", "invalid", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		try {
+			xdg.runtimeDir();
+
+			ASSERT_TRUE(false);
+		} catch (const std::exception &) { }
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(DirectoriesEmpty, config)
+{
+	ASSERT_TRUE(unsetenv("XDG_CONFIG_DIRS") == 0);
+
+	try {
+		Xdg xdg;
+
+		const auto &list = xdg.configDirs();
+
+		ASSERT_EQ((size_t)1, list.size());
+		ASSERT_EQ("/etc/xdg", list[0]);
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(DirectoriesEmpty, data)
+{
+	ASSERT_TRUE(unsetenv("XDG_DATA_DIRS") == 0);
+
+	try {
+		Xdg xdg;
+
+		const auto &list = xdg.dataDirs();
+
+		ASSERT_EQ((size_t)2, list.size());
+		ASSERT_EQ("/usr/local/share", list[0]);
+		ASSERT_EQ("/usr/share", list[1]);
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(DirectoriesValid, config)
+{
+	ASSERT_TRUE(setenv("XDG_CONFIG_DIRS", "/config1:/config2", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		const auto &list = xdg.configDirs();
+
+		ASSERT_EQ((size_t)2, list.size());
+		ASSERT_EQ("/config1", list[0]);
+		ASSERT_EQ("/config2", list[1]);
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(DirectoriesValid, data)
+{
+	ASSERT_TRUE(setenv("XDG_DATA_DIRS", "/data1:/data2", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		const auto &list = xdg.dataDirs();
+
+		ASSERT_EQ((size_t)2, list.size());
+		ASSERT_EQ("/data1", list[0]);
+		ASSERT_EQ("/data2", list[1]);
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(DirectoriesInvalid, config)
+{
+	ASSERT_TRUE(setenv("XDG_CONFIG_DIRS", "bad1:bad2", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		const auto &list = xdg.configDirs();
+
+		ASSERT_EQ((size_t)1, list.size());
+		ASSERT_EQ("/etc/xdg", list[0]);
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(DirectoriesInvalid, data)
+{
+	ASSERT_TRUE(setenv("XDG_DATA_DIRS", "bad1:bad2", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		const auto &list = xdg.dataDirs();
+
+		ASSERT_EQ((size_t)2, list.size());
+		ASSERT_EQ("/usr/local/share", list[0]);
+		ASSERT_EQ("/usr/share", list[1]);
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(DirectoriesMixed, config)
+{
+	ASSERT_TRUE(setenv("XDG_CONFIG_DIRS", "/config1:bad:/config2", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		const auto &list = xdg.configDirs();
+
+		ASSERT_EQ((size_t)2, list.size());
+		ASSERT_EQ("/config1", list[0]);
+		ASSERT_EQ("/config2", list[1]);
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+TEST(DirectoriesMixed, data)
+{
+	ASSERT_TRUE(setenv("XDG_DATA_DIRS", "/data1:bad:/data2", true) == 0);
+
+	try {
+		Xdg xdg;
+
+		const auto &list = xdg.dataDirs();
+
+		ASSERT_EQ((size_t)2, list.size());
+		ASSERT_EQ("/data1", list[0]);
+		ASSERT_EQ("/data2", list[1]);
+	} catch (const std::exception &) {
+		ASSERT_TRUE(false);
+	}
+}
+
+int main(int argc, char **argv)
+{
+	auto home = getenv("HOME");
+
+	if (home == nullptr)
+		return 0;
+
+	myhome = home;
+	InitGoogleTest(&argc, argv);
+
+	return RUN_ALL_TESTS();
+}
--- a/C++/Xdg.cpp	Tue Aug 12 16:45:33 2014 +0200
+++ b/C++/Xdg.cpp	Thu Aug 14 09:56:25 2014 +0200
@@ -17,12 +17,18 @@
  */
 
 #include <cstdlib>
+#include <stdexcept>
 #include <sstream>
 
-#include "xdg.h"
+#include "Xdg.h"
 
 namespace {
 
+bool isabsolute(const std::string &path)
+{
+	return path.length() > 0 && path[0] == '/';
+}
+
 std::vector<std::string> split(const std::string &arg)
 {
 	std::stringstream iss(arg);
@@ -30,7 +36,8 @@
 	std::vector<std::string> elems;
 
 	while (std::getline(iss, item, ':'))
-		elems.push_back(item);
+		if (isabsolute(item))
+			elems.push_back(item);
 
 	return elems;
 }
@@ -39,7 +46,7 @@
 {
 	auto value = getenv(var.c_str());
 
-	if (value == nullptr) {
+	if (value == nullptr || !isabsolute(value)) {
 		auto home = getenv("HOME");
 
 		if (home == nullptr)
@@ -58,7 +65,10 @@
 	if (!value)
 		return list;
 
-	return split(value);
+	// No valid item at all? Use defaults
+	auto result = split(value);
+
+	return (result.size() == 0) ? list : result;
 }
 
 } // !namespace
@@ -77,7 +87,7 @@
 	 * application should manage this by itself.
 	 */
 	auto runtime = getenv("XDG_RUNTIME_DIR");
-	if (runtime)
+	if (runtime && isabsolute(runtime))
 		m_runtimeDir = runtime;
 }
 
--- a/C++/Xdg.h	Tue Aug 12 16:45:33 2014 +0200
+++ b/C++/Xdg.h	Thu Aug 14 09:56:25 2014 +0200
@@ -36,7 +36,8 @@
  * @class Xdg
  * @brief XDG specifications
  *
- * Read and get XDG directories.
+ * Read and get XDG directories. This file contains exports thingies so it can
+ * compiles successfully on Windows but its usage is discouraged.
  */
 class EXPORT Xdg {
 public:
--- a/CMakeLists.txt	Tue Aug 12 16:45:33 2014 +0200
+++ b/CMakeLists.txt	Thu Aug 14 09:56:25 2014 +0200
@@ -68,6 +68,7 @@
 option(WITH_SOCKET "Enable sockets tests" On)
 option(WITH_UTF8 "Enable Utf8 functions tests" On)
 option(WITH_XMLPARSER "Enable XML tests" On)
+option(WITH_XDG "Enable XDG standard directories tests" On)
 
 if (WITH_DIRECTORY)
 	add_subdirectory(C++/Tests/Directory)
@@ -96,3 +97,7 @@
 if (WITH_PARSER)
 	add_subdirectory(C++/Tests/Parser)
 endif ()
+
+if (WITH_XDG)
+	add_subdirectory(C++/Tests/Xdg)
+endif ()