mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 03:37:59 +01:00
common: do not accept invalid input in VersionHelper and add negative unit tests
This commit is contained in:
committed by
Andrey Nekrasov
parent
870f1095cd
commit
fc4ac803aa
@@ -4,11 +4,20 @@
|
|||||||
|
|
||||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||||
|
|
||||||
|
namespace Microsoft::VisualStudio::CppUnitTestFramework
|
||||||
|
{
|
||||||
|
template<>
|
||||||
|
inline std::wstring ToString<VersionHelper>(const VersionHelper& v)
|
||||||
|
{
|
||||||
|
return v.toWstring();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace UnitTestsVersionHelper
|
namespace UnitTestsVersionHelper
|
||||||
{
|
{
|
||||||
const int MAJOR_VERSION_0 = 0;
|
const size_t MAJOR_VERSION_0 = 0;
|
||||||
const int MINOR_VERSION_12 = 12;
|
const size_t MINOR_VERSION_12 = 12;
|
||||||
const int REVISION_VERSION_0 = 0;
|
const size_t REVISION_VERSION_0 = 0;
|
||||||
|
|
||||||
TEST_CLASS (UnitTestsVersionHelper)
|
TEST_CLASS (UnitTestsVersionHelper)
|
||||||
{
|
{
|
||||||
@@ -23,9 +32,9 @@ namespace UnitTestsVersionHelper
|
|||||||
}
|
}
|
||||||
TEST_METHOD (integerConstructorShouldProperlyInitializationWithDifferentVersionNumbers)
|
TEST_METHOD (integerConstructorShouldProperlyInitializationWithDifferentVersionNumbers)
|
||||||
{
|
{
|
||||||
const int testcaseMajor = 2;
|
const size_t testcaseMajor = 2;
|
||||||
const int testcaseMinor = 25;
|
const size_t testcaseMinor = 25;
|
||||||
const int testcaseRevision = 1;
|
const size_t testcaseRevision = 1;
|
||||||
VersionHelper sut(testcaseMajor, testcaseMinor, testcaseRevision);
|
VersionHelper sut(testcaseMajor, testcaseMinor, testcaseRevision);
|
||||||
|
|
||||||
Assert::AreEqual(testcaseMajor, sut.major);
|
Assert::AreEqual(testcaseMajor, sut.major);
|
||||||
@@ -36,17 +45,77 @@ namespace UnitTestsVersionHelper
|
|||||||
{
|
{
|
||||||
VersionHelper sut("v0.12.3");
|
VersionHelper sut("v0.12.3");
|
||||||
|
|
||||||
Assert::AreEqual(0, sut.major);
|
Assert::AreEqual(0ull, sut.major);
|
||||||
Assert::AreEqual(12, sut.minor);
|
Assert::AreEqual(12ull, sut.minor);
|
||||||
Assert::AreEqual(3, sut.revision);
|
Assert::AreEqual(3ull, sut.revision);
|
||||||
}
|
}
|
||||||
TEST_METHOD (stringConstructorShouldProperlyInitializationWithDifferentVersionNumbers)
|
TEST_METHOD (stringConstructorShouldProperlyInitializationWithDifferentVersionNumbers)
|
||||||
{
|
{
|
||||||
VersionHelper sut("v2.25.1");
|
VersionHelper sut("v2.25.1");
|
||||||
|
|
||||||
Assert::AreEqual(2, sut.major);
|
Assert::AreEqual(2ull, sut.major);
|
||||||
Assert::AreEqual(25, sut.minor);
|
Assert::AreEqual(25ull, sut.minor);
|
||||||
Assert::AreEqual(1, sut.revision);
|
Assert::AreEqual(1ull, sut.revision);
|
||||||
|
}
|
||||||
|
TEST_METHOD (emptyStringNotAccepted)
|
||||||
|
{
|
||||||
|
Assert::ExpectException<std::logic_error>([] {
|
||||||
|
VersionHelper sut("");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
TEST_METHOD (invalidStringNotAccepted1)
|
||||||
|
{
|
||||||
|
Assert::ExpectException<std::logic_error>([] {
|
||||||
|
VersionHelper sut("v2a.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
TEST_METHOD (invalidStringNotAccepted2)
|
||||||
|
{
|
||||||
|
Assert::ExpectException<std::logic_error>([] {
|
||||||
|
VersionHelper sut("12abc2vv.0");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
TEST_METHOD (invalidStringNotAccepted3)
|
||||||
|
{
|
||||||
|
Assert::ExpectException<std::logic_error>([] {
|
||||||
|
VersionHelper sut("123");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
TEST_METHOD (invalidStringNotAccepted4)
|
||||||
|
{
|
||||||
|
Assert::ExpectException<std::logic_error>([] {
|
||||||
|
VersionHelper sut("v1v2v3");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
TEST_METHOD (invalidStringNotAccepted5)
|
||||||
|
{
|
||||||
|
Assert::ExpectException<std::logic_error>([] {
|
||||||
|
VersionHelper sut("v.1.2.3v");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
TEST_METHOD (partialVersionStringNotAccepted1)
|
||||||
|
{
|
||||||
|
Assert::ExpectException<std::logic_error>([] {
|
||||||
|
VersionHelper sut("v1.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
TEST_METHOD (partialVersionStringNotAccepted2)
|
||||||
|
{
|
||||||
|
Assert::ExpectException<std::logic_error>([] {
|
||||||
|
VersionHelper sut("v1.2");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
TEST_METHOD (partialVersionStringNotAccepted3)
|
||||||
|
{
|
||||||
|
Assert::ExpectException<std::logic_error>([] {
|
||||||
|
VersionHelper sut("v1.2.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
TEST_METHOD (parsedWithoutLeadingV)
|
||||||
|
{
|
||||||
|
VersionHelper expected{ 12ull, 13ull, 111ull };
|
||||||
|
VersionHelper actual("12.13.111");
|
||||||
|
Assert::AreEqual(actual, expected);
|
||||||
}
|
}
|
||||||
TEST_METHOD (whenMajorVersionIsGreaterComparisonOperatorShouldReturnProperValue)
|
TEST_METHOD (whenMajorVersionIsGreaterComparisonOperatorShouldReturnProperValue)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,30 +1,32 @@
|
|||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
#include "VersionHelper.h"
|
#include "VersionHelper.h"
|
||||||
|
|
||||||
|
#include "string_utils.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
VersionHelper::VersionHelper(std::string str)
|
VersionHelper::VersionHelper(std::string str)
|
||||||
{
|
{
|
||||||
std::replace(str.begin(), str.end(), '.', ' ');
|
// Remove whitespaces chars and a leading 'v'
|
||||||
std::replace(str.begin(), str.end(), 'v', ' ');
|
str = left_trim(trim(str), "v");
|
||||||
std::stringstream ss;
|
// Replace '.' with spaces
|
||||||
|
replace_chars(str, ".", ' ');
|
||||||
|
|
||||||
ss << str;
|
std::istringstream ss{ str };
|
||||||
|
ss >> major;
|
||||||
std::string temp;
|
ss >> minor;
|
||||||
ss >> temp;
|
ss >> revision;
|
||||||
std::stringstream(temp) >> major;
|
if (ss.fail() || !ss.eof())
|
||||||
ss >> temp;
|
{
|
||||||
std::stringstream(temp) >> minor;
|
throw std::logic_error("VersionHelper: couldn't parse the supplied version string");
|
||||||
ss >> temp;
|
}
|
||||||
std::stringstream(temp) >> revision;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VersionHelper::VersionHelper(int major, int minor, int revision) :
|
VersionHelper::VersionHelper(const size_t major, const size_t minor, const size_t revision) :
|
||||||
major(major),
|
major{ major },
|
||||||
minor(minor),
|
minor{ minor },
|
||||||
revision(revision)
|
revision{ revision }
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,13 +6,13 @@
|
|||||||
struct VersionHelper
|
struct VersionHelper
|
||||||
{
|
{
|
||||||
VersionHelper(std::string str);
|
VersionHelper(std::string str);
|
||||||
VersionHelper(int major, int minor, int revision);
|
VersionHelper(const size_t major, const size_t minor, const size_t revision);
|
||||||
|
|
||||||
auto operator<=>(const VersionHelper&) const = default;
|
auto operator<=>(const VersionHelper&) const = default;
|
||||||
|
|
||||||
int major;
|
size_t major;
|
||||||
int minor;
|
size_t minor;
|
||||||
int revision;
|
size_t revision;
|
||||||
|
|
||||||
std::wstring toWstring() const;
|
std::wstring toWstring() const;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -138,6 +138,7 @@
|
|||||||
<ClInclude Include="os-detect.h" />
|
<ClInclude Include="os-detect.h" />
|
||||||
<ClInclude Include="RestartManagement.h" />
|
<ClInclude Include="RestartManagement.h" />
|
||||||
<ClInclude Include="shared_constants.h" />
|
<ClInclude Include="shared_constants.h" />
|
||||||
|
<ClInclude Include="string_utils.h" />
|
||||||
<ClInclude Include="timeutil.h" />
|
<ClInclude Include="timeutil.h" />
|
||||||
<ClInclude Include="two_way_pipe_message_ipc.h" />
|
<ClInclude Include="two_way_pipe_message_ipc.h" />
|
||||||
<ClInclude Include="VersionHelper.h" />
|
<ClInclude Include="VersionHelper.h" />
|
||||||
|
|||||||
@@ -131,13 +131,16 @@
|
|||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="comUtils.h">
|
<ClInclude Include="comUtils.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="LowlevelKeyboardEvent.h">
|
<ClInclude Include="LowlevelKeyboardEvent.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="WinHookEvent.h">
|
<ClInclude Include="WinHookEvent.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="string_utils.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="d2d_svg.cpp">
|
<ClCompile Include="d2d_svg.cpp">
|
||||||
@@ -223,4 +226,4 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -34,10 +34,10 @@ D2DSVG& D2DSVG::resize(int x, int y, int width, int height, float fill, float ma
|
|||||||
transform = transform * D2D1::Matrix3x2F::Translation((width - svg_width) / 2.0f, (height - svg_height) / 2.0f);
|
transform = transform * D2D1::Matrix3x2F::Translation((width - svg_width) / 2.0f, (height - svg_height) / 2.0f);
|
||||||
float h_scale = fill * height / svg_height;
|
float h_scale = fill * height / svg_height;
|
||||||
float v_scale = fill * width / svg_width;
|
float v_scale = fill * width / svg_width;
|
||||||
used_scale = min(h_scale, v_scale);
|
used_scale = std::min(h_scale, v_scale);
|
||||||
if (max_scale > 0)
|
if (max_scale > 0)
|
||||||
{
|
{
|
||||||
used_scale = min(used_scale, max_scale);
|
used_scale = std::min(used_scale, max_scale);
|
||||||
}
|
}
|
||||||
transform = transform * D2D1::Matrix3x2F::Scale(used_scale, used_scale, D2D1::Point2F(width / 2.0f, height / 2.0f));
|
transform = transform * D2D1::Matrix3x2F::Scale(used_scale, used_scale, D2D1::Point2F(width / 2.0f, height / 2.0f));
|
||||||
transform = transform * D2D1::Matrix3x2F::Translation((float)x, (float)y);
|
transform = transform * D2D1::Matrix3x2F::Translation((float)x, (float)y);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#define NOMINMAX
|
||||||
#include <winrt/base.h>
|
#include <winrt/base.h>
|
||||||
#include <winrt/Windows.Foundation.Collections.h>
|
#include <winrt/Windows.Foundation.Collections.h>
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|||||||
32
src/common/string_utils.h
Normal file
32
src/common/string_utils.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
constexpr inline std::string_view default_trim_arg = " \t\r\n";
|
||||||
|
|
||||||
|
inline std::string_view left_trim(std::string_view s, const std::string_view chars_to_trim = default_trim_arg)
|
||||||
|
{
|
||||||
|
s.remove_prefix(std::min(s.find_first_not_of(chars_to_trim), size(s)));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string_view right_trim(std::string_view s, const std::string_view chars_to_trim = default_trim_arg)
|
||||||
|
{
|
||||||
|
s.remove_suffix(std::min(size(s) - s.find_last_not_of(chars_to_trim) - 1, size(s)));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string_view trim(std::string_view s, const std::string_view chars_to_trim = default_trim_arg)
|
||||||
|
{
|
||||||
|
return left_trim(right_trim(s, chars_to_trim), chars_to_trim);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void replace_chars(std::string& s, const std::string_view chars_to_replace, const char replacement_char)
|
||||||
|
{
|
||||||
|
for (const char c : chars_to_replace)
|
||||||
|
{
|
||||||
|
std::replace(begin(s), end(s), c, replacement_char);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user