From dcf2375a770587558b70f273eb0fd293a09437be Mon Sep 17 00:00:00 2001 From: Sunius Date: Tue, 21 Oct 2014 00:23:18 +0300 Subject: [PATCH] Added 5 tests and fixed a bug in the process! --- .gitignore | 1 + .../RemoteFileBrowser/LoggingTests.cpp | 173 +++++++++++++++++- .../RemoteFileBrowser.vcxproj | 2 +- .../Utilities/CriticalSection.h | 2 +- .../RemoteFileBrowser/Utilities/Utilities.cpp | 17 +- .../RemoteFileBrowser/Utilities/Utilities.h | 11 +- .../RemoteFileBrowser/Utilities/Utilities.inl | 16 +- 7 files changed, 185 insertions(+), 37 deletions(-) diff --git a/.gitignore b/.gitignore index f95c8cc..8e52873 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ x64/ build/ [Bb]in/ [Oo]bj/ +Intermediate/ # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets !packages/*/build/ diff --git a/RemoteFileBrowser/RemoteFileBrowser/LoggingTests.cpp b/RemoteFileBrowser/RemoteFileBrowser/LoggingTests.cpp index aa33e5c..df32f63 100644 --- a/RemoteFileBrowser/RemoteFileBrowser/LoggingTests.cpp +++ b/RemoteFileBrowser/RemoteFileBrowser/LoggingTests.cpp @@ -1,18 +1,175 @@ #include "PrecompiledHeader.h" + +#if _TESTBUILD + #include "CppUnitTest.h" +#include "Utilities\Utilities.h" using namespace Microsoft::VisualStudio::CppUnitTestFramework; +using namespace std; +using namespace Utilities; -namespace RemoteFileBrowser +TEST_CLASS(LoggingTests) { - TEST_CLASS(LoggingTests) +private: + wstring m_LogFileName; + +public: + LoggingTests() : + m_LogFileName(Logging::GetLogFileName()) { - public: - - TEST_METHOD(TestMethod1) + } + + template + void DoTest(LogAction logAction, AssertAction assertAction) + { + Logging::Initialize(true); + logAction(); + Logging::Shutdown(); + + assertAction(); + } + + vector GetLogFileContents() + { + wifstream in(m_LogFileName); + vector input; + wstring line; + + while (!in.eof()) { - // TODO: Your test code here + getline(in, line); + + if (!in.fail()) + { + input.push_back(move(line)); + } } - }; -} \ No newline at end of file + return input; + } + + void AssertEndsWith(const wstring& expected, const wstring& actual) + { + Assert::AreEqual(expected.c_str(), actual.c_str() + actual.length() - expected.length()); + } + + void AssertEndsWith(const vector& expectedLines, const vector& actualLines) + { + Assert::AreEqual(expectedLines.size(), actualLines.size()); + + for (auto i = 0u; i < actualLines.size(); i++) + { + AssertEndsWith(expectedLines[i], actualLines[i]); + } + } + + TEST_METHOD(CanOutputMessage) + { + DoTest( + []() + { + Logging::OutputMessage("Hello, world!"); + }, + + [this]() + { + Assert::AreEqual(L"Hello, world!", GetLogFileContents()[0].c_str()); + } + ); + } + + TEST_METHOD(CanLogOnce) + { + DoTest( + []() + { + Logging::Log("Hello, world!"); + }, + + [this]() + { + AssertEndsWith(L"Hello, world!", GetLogFileContents()[0]); + } + ); + } + + TEST_METHOD(CanLogMultipleMessages) + { + DoTest( + []() + { + Logging::Log("Hell", "o, w", "orld!"); + }, + + [this]() + { + AssertEndsWith(L"Hello, world!", GetLogFileContents()[0].c_str()); + } + ); + } + + TEST_METHOD(CanLogMultipleTimes) + { + DoTest( + []() + { + Logging::Log("Hello, world!"); + Logging::Log("Hello, world!"); + Logging::Log("Hello, world!"); + }, + + [this]() + { + vector expected; + expected.push_back(L"Hello, world!"); + expected.push_back(L"Hello, world!"); + expected.push_back(L"Hello, world!"); + AssertEndsWith(expected, GetLogFileContents()); + } + ); + } + + static const int kThreadCountForThreadSafeTest = 10; + static const int kMessagesPerThreadForThreadSafeTest = 20; + + TEST_METHOD(LogIsThreadSafe) + { + DoTest( + []() + { + thread threads[kThreadCountForThreadSafeTest]; + + for (int i = 0; i < kThreadCountForThreadSafeTest; i++) + { + threads[i] = thread([]() + { + for (int j = 0; j < kMessagesPerThreadForThreadSafeTest; j++) + { + Logging::Log("Hello, world!"); + } + }); + } + + for (int i = 0; i < kThreadCountForThreadSafeTest; i++) + { + threads[i].join(); + } + }, + + [this]() + { + vector expected; + + for (int i = 0; i < kThreadCountForThreadSafeTest * kMessagesPerThreadForThreadSafeTest; i++) + { + expected.push_back(L"Hello, world!"); + } + + AssertEndsWith(expected, GetLogFileContents()); + } + ); + } +}; + +#endif // _TESTBUILD \ No newline at end of file diff --git a/RemoteFileBrowser/RemoteFileBrowser/RemoteFileBrowser.vcxproj b/RemoteFileBrowser/RemoteFileBrowser/RemoteFileBrowser.vcxproj index 5402f5a..5af610d 100644 --- a/RemoteFileBrowser/RemoteFileBrowser/RemoteFileBrowser.vcxproj +++ b/RemoteFileBrowser/RemoteFileBrowser/RemoteFileBrowser.vcxproj @@ -90,7 +90,7 @@ Use Level3 Disabled - WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + WIN32;_DEBUG;_TESTBUILD;_WINDOWS;%(PreprocessorDefinitions) true PrecompiledHeader.h $(ProjectDir) diff --git a/RemoteFileBrowser/RemoteFileBrowser/Utilities/CriticalSection.h b/RemoteFileBrowser/RemoteFileBrowser/Utilities/CriticalSection.h index 0d5cc67..a832b07 100644 --- a/RemoteFileBrowser/RemoteFileBrowser/Utilities/CriticalSection.h +++ b/RemoteFileBrowser/RemoteFileBrowser/Utilities/CriticalSection.h @@ -32,7 +32,7 @@ class CriticalSection CriticalSection& m_Section; public: - inline Lock(CriticalSection criticalSection) : + inline Lock(CriticalSection& criticalSection) : m_Section(criticalSection) { m_Section.Enter(); diff --git a/RemoteFileBrowser/RemoteFileBrowser/Utilities/Utilities.cpp b/RemoteFileBrowser/RemoteFileBrowser/Utilities/Utilities.cpp index a04a46f..f0be8d3 100644 --- a/RemoteFileBrowser/RemoteFileBrowser/Utilities/Utilities.cpp +++ b/RemoteFileBrowser/RemoteFileBrowser/Utilities/Utilities.cpp @@ -10,9 +10,11 @@ CriticalSection Logging::s_LogCriticalSection; static HANDLE s_OutputFile; static const wchar_t kLogFileName[] = L"LogFile.log"; -void Logging::Initialize() +void Logging::Initialize(bool forceOverwrite) { - s_OutputFile = CreateFile(kLogFileName, FILE_GENERIC_WRITE, FILE_SHARE_READ, nullptr, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr); + auto openMode = forceOverwrite ? CREATE_ALWAYS : CREATE_NEW; + s_OutputFile = CreateFile(kLogFileName, FILE_GENERIC_WRITE, FILE_SHARE_READ, nullptr, openMode, FILE_ATTRIBUTE_NORMAL, nullptr); + Assert(s_OutputFile != INVALID_HANDLE_VALUE || !forceOverwrite); if (s_OutputFile == INVALID_HANDLE_VALUE) { @@ -28,6 +30,8 @@ void Logging::Initialize() Assert(result != FALSE); Assert(bytesWritten = sizeof(threeNewLines)); } + + SetLastError(ERROR_SUCCESS); } void Logging::Shutdown() @@ -35,6 +39,11 @@ void Logging::Shutdown() CloseHandle(s_OutputFile); } +std::wstring Logging::GetLogFileName() +{ + return kLogFileName; +} + void Logging::OutputMessage(const char* message, size_t length) { if (IsDebuggerPresent()) @@ -71,8 +80,8 @@ void Logging::OutputCurrentTimestamp() char buffer[kBufferSize]; wchar_t wbuffer[kBufferSize]; - SystemTimeToStringInline(wbuffer); - Encoding::Utf16ToUtf8Inline(wbuffer, buffer); + auto dateTimeLength = SystemTimeToStringInline(wbuffer); + Encoding::Utf16ToUtf8Inline(wbuffer, dateTimeLength, buffer, kBufferSize); OutputMessage(buffer); OutputMessage("] "); diff --git a/RemoteFileBrowser/RemoteFileBrowser/Utilities/Utilities.h b/RemoteFileBrowser/RemoteFileBrowser/Utilities/Utilities.h index e021706..c986045 100644 --- a/RemoteFileBrowser/RemoteFileBrowser/Utilities/Utilities.h +++ b/RemoteFileBrowser/RemoteFileBrowser/Utilities/Utilities.h @@ -32,8 +32,9 @@ namespace Utilities template static inline void LogFatalErrorIfFailed(bool failed, Message&& ...message); - static void Initialize(); + static void Initialize(bool forceOverwrite = false); static void Shutdown(); + static std::wstring GetLogFileName(); Logging() = delete; Logging(const Logging&) = delete; @@ -58,18 +59,10 @@ namespace Utilities namespace Encoding { size_t Utf8ToUtf16Inline(const char* str, size_t strLength, wchar_t* destination, size_t destinationLength); - - template - inline size_t Utf8ToUtf16Inline(const char (&str)[SourceLength], wchar_t (&destination)[DestinationLength]); - std::wstring Utf8ToUtf16(const char* str, size_t strLength); inline std::wstring Utf8ToUtf16(const std::string& str); size_t Utf16ToUtf8Inline(const wchar_t* wstr, size_t wstrLength, char* destination, size_t destinationLength); - - template - inline size_t Utf16ToUtf8Inline(const wchar_t (&wstr)[SourceLength], char (&destination)[DestinationLength]); - std::string Utf16ToUtf8(const wchar_t* wstr, size_t wstrLength); inline std::string Utf16ToUtf8(const std::wstring& wstr); diff --git a/RemoteFileBrowser/RemoteFileBrowser/Utilities/Utilities.inl b/RemoteFileBrowser/RemoteFileBrowser/Utilities/Utilities.inl index f6d0982..dbdc806 100644 --- a/RemoteFileBrowser/RemoteFileBrowser/Utilities/Utilities.inl +++ b/RemoteFileBrowser/RemoteFileBrowser/Utilities/Utilities.inl @@ -22,8 +22,8 @@ inline void Utilities::Logging::Win32ErrorToMessageInline(int win32ErrorCode, ch { wchar_t wBuffer[kBufferSize]; - FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, win32ErrorCode, 0, wBuffer, kBufferSize, nullptr); - Utilities::Encoding::Utf16ToUtf8Inline(wBuffer, buffer); + auto messageLength = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, win32ErrorCode, 0, wBuffer, kBufferSize, nullptr); + Utilities::Encoding::Utf16ToUtf8Inline(wBuffer, messageLength, buffer, kBufferSize); } template @@ -118,23 +118,11 @@ inline void Utilities::Logging::LogFatalErrorIfFailed(bool failed, Message&& ... // Encoding -template -inline size_t Utilities::Encoding::Utf8ToUtf16Inline(const char (&str)[SourceLength], wchar_t (&destination)[DestinationLength]) -{ - return Utf8ToUtf16Inline(str, SourceLength, destination, DestinationLength); -} - inline std::wstring Utilities::Encoding::Utf8ToUtf16(const std::string& str) { return Utf8ToUtf16(str.c_str(), str.length()); } -template -inline size_t Utilities::Encoding::Utf16ToUtf8Inline(const wchar_t(&wstr)[SourceLength], char(&destination)[DestinationLength]) -{ - return Utf16ToUtf8Inline(wstr, SourceLength, destination, DestinationLength); -} - inline std::string Utilities::Encoding::Utf16ToUtf8(const std::wstring& wstr) { return Utf16ToUtf8(wstr.c_str(), wstr.length());