diff --git a/Common/Common_Test.vcxproj b/Common/Common_Test.vcxproj
new file mode 100644
index 00000000..16995f6c
--- /dev/null
+++ b/Common/Common_Test.vcxproj
@@ -0,0 +1,25 @@
+
+
+
+
+ {442084A6-2069-4927-B0C9-51525A720CB2}
+ DynamicLibrary
+
+
+
+
+
+ $(IntDir)
+
+
+
+
+
+
+ {19312085-aa51-4bd6-be92-4b6098cca539}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Common/Common_Test.vcxproj.filters b/Common/Common_Test.vcxproj.filters
new file mode 100644
index 00000000..ce87eb69
--- /dev/null
+++ b/Common/Common_Test.vcxproj.filters
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Common/PathUtil_Test.cpp b/Common/PathUtil_Test.cpp
new file mode 100644
index 00000000..61d920ef
--- /dev/null
+++ b/Common/PathUtil_Test.cpp
@@ -0,0 +1,108 @@
+/*
+ Copyright (C) 2013 Rainmeter Team
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include "CppUnitTest.h"
+#include "PathUtil.h"
+#include
+
+using namespace Microsoft::VisualStudio::CppUnitTestFramework;
+
+namespace PathUtil {
+
+TEST_CLASS(Common_PathUtil_Test)
+{
+public:
+ TEST_METHOD(TestIsSeparator)
+ {
+ Assert::IsTrue(IsSeparator(L'\\'));
+ Assert::IsTrue(IsSeparator(L'/'));
+ Assert::IsFalse(IsSeparator(L'.'));
+ }
+
+ TEST_METHOD(TestIsDotOrDotDot)
+ {
+ Assert::IsTrue(IsDotOrDotDot(L"."));
+ Assert::IsTrue(IsDotOrDotDot(L".."));
+ Assert::IsFalse(IsDotOrDotDot(L"..."));
+ Assert::IsFalse(IsDotOrDotDot(L""));
+ }
+
+ TEST_METHOD(TestIsUNC)
+ {
+ Assert::IsTrue(IsUNC(L"\\\\server"));
+ Assert::IsTrue(IsUNC(L"//server"));
+ }
+
+ TEST_METHOD(TestIsAbsolute)
+ {
+ Assert::IsTrue(IsAbsolute(L"\\\\server"));
+ Assert::IsTrue(IsAbsolute(L"C:\\test"));
+ Assert::IsTrue(IsAbsolute(L"C:/test"));
+ Assert::IsFalse(IsAbsolute(L"C:"));
+ }
+
+ TEST_METHOD(TestAppendBacklashIfMissing)
+ {
+ std::wstring path;
+ AppendBacklashIfMissing(path);
+ Assert::IsTrue(path.empty());
+
+ std::wstring path2 = L"C:\\test";
+ AppendBacklashIfMissing(path2);
+ Assert::IsTrue(path2 == L"C:\\test\\");
+
+ std::wstring path3 = L"C:\\test\\";
+ AppendBacklashIfMissing(path3);
+ Assert::IsTrue(path3 == L"C:\\test\\");
+ }
+
+ TEST_METHOD(TestGetFolderFromFilePath)
+ {
+ Assert::IsTrue(GetFolderFromFilePath(L"C:\\test.txt") == L"C:\\");
+ }
+
+ TEST_METHOD(TestGetVolume)
+ {
+ Assert::IsTrue(GetVolume(L"C:\\test.txt") == L"C:");
+ Assert::IsTrue(GetVolume(L"\\\\server\\share\\") == L"\\\\server\\share");
+ Assert::IsTrue(GetVolume(L"\\\\server\\C:\\path\\") == L"\\\\server\\C:");
+ }
+
+ TEST_METHOD(TestExpandEnvironmentVariables)
+ {
+ WCHAR appdataPath[MAX_PATH];
+ SHGetFolderPath(nullptr, CSIDL_APPDATA, nullptr, SHGFP_TYPE_CURRENT, appdataPath);
+
+ WCHAR windirPath[MAX_PATH];
+ ExpandEnvironmentStrings(L"%WINDIR%", windirPath, MAX_PATH);
+
+ std::wstring test = L"%APPDATA%";
+ PathUtil::ExpandEnvironmentVariables(test);
+ Assert::IsTrue(test == appdataPath);
+
+ std::wstring test2 = L"%APPDATA%%WINDIR%";
+ PathUtil::ExpandEnvironmentVariables(test2);
+ Assert::IsTrue(test2 == ((std::wstring)appdataPath + windirPath));
+
+ std::wstring test3 = L"%APPDATA%%WINDIR%%APPDATA%";
+ PathUtil::ExpandEnvironmentVariables(test3);
+ Assert::IsTrue(test3 == ((std::wstring)appdataPath + windirPath + appdataPath));
+ }
+};
+
+} // namespace PathUtil
diff --git a/Rainmeter.props b/Rainmeter.props
index 15dfc0f0..5a9bf606 100644
--- a/Rainmeter.props
+++ b/Rainmeter.props
@@ -32,11 +32,14 @@
+ $(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories)
+
WIN32;_WINDOWS;WINVER=0x0601;_WIN32_WINNT=0x0601;_WIN32_IE=0x0601;PSAPI_VERSION=1;%(PreprocessorDefinitions)
Level3
+ $(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)
$(IntDir)$(TargetName).lib
$(IntDir)$(TargetName).pdb
false
diff --git a/Rainmeter.sln b/Rainmeter.sln
index a6b4e0a9..5b45c60a 100644
--- a/Rainmeter.sln
+++ b/Rainmeter.sln
@@ -63,6 +63,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PluginWin7Audio", "Plugins\
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PluginWindowMessage", "Plugins\PluginWindowMessage\PluginWindowMessage.vcxproj", "{B9184DBA-C6B7-44FE-8BBD-0852DB22D2E4}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common_Test", "Common\Common_Test.vcxproj", "{442084A6-2069-4927-B0C9-51525A720CB2}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -299,6 +301,12 @@ Global
{B9184DBA-C6B7-44FE-8BBD-0852DB22D2E4}.Release|Win32.Build.0 = Release|Win32
{B9184DBA-C6B7-44FE-8BBD-0852DB22D2E4}.Release|x64.ActiveCfg = Release|x64
{B9184DBA-C6B7-44FE-8BBD-0852DB22D2E4}.Release|x64.Build.0 = Release|x64
+ {442084A6-2069-4927-B0C9-51525A720CB2}.Debug|Win32.ActiveCfg = Debug|Win32
+ {442084A6-2069-4927-B0C9-51525A720CB2}.Debug|Win32.Build.0 = Debug|Win32
+ {442084A6-2069-4927-B0C9-51525A720CB2}.Debug|x64.ActiveCfg = Debug|x64
+ {442084A6-2069-4927-B0C9-51525A720CB2}.Debug|x64.Build.0 = Debug|x64
+ {442084A6-2069-4927-B0C9-51525A720CB2}.Release|Win32.ActiveCfg = Release|Win32
+ {442084A6-2069-4927-B0C9-51525A720CB2}.Release|x64.ActiveCfg = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE