[PowerRename] Introduce advanced counter functionality (#27895)

This commit is contained in:
Andrey Nekrasov
2023-08-14 16:53:49 +02:00
committed by GitHub
parent 97d397a576
commit 268614ccd9
24 changed files with 819 additions and 717 deletions

View File

@@ -2003,6 +2003,7 @@ unregistering
unremapped unremapped
unsubscribe unsubscribe
unvirtualized unvirtualized
unwide
UOffset UOffset
UOI UOI
Updatelayout Updatelayout

View File

@@ -54,3 +54,12 @@ inline void replace_chars(std::basic_string<CharT>& s,
std::replace(begin(s), end(s), c, replacement_char); std::replace(begin(s), end(s), c, replacement_char);
} }
} }
inline std::string unwide(const std::wstring& wide)
{
std::string result(wide.length(), 0);
std::transform(begin(wide), end(wide), result.begin(), [](const wchar_t c) {
return static_cast<char>(c);
});
return result;
}

View File

@@ -14,6 +14,7 @@ namespace PowerRenameUI
ExplorerItemsSource ExplorerItems { get; }; ExplorerItemsSource ExplorerItems { get; };
Windows.Foundation.Collections.IObservableVector<PatternSnippet> SearchRegExShortcuts { get; }; Windows.Foundation.Collections.IObservableVector<PatternSnippet> SearchRegExShortcuts { get; };
Windows.Foundation.Collections.IObservableVector<PatternSnippet> DateTimeShortcuts { get; }; Windows.Foundation.Collections.IObservableVector<PatternSnippet> DateTimeShortcuts { get; };
Windows.Foundation.Collections.IObservableVector<PatternSnippet> CounterShortcuts { get; };
String OriginalCount; String OriginalCount;
String RenamedCount; String RenamedCount;

View File

@@ -323,6 +323,8 @@
<Flyout x:Name="DateTimeFlyout" ShouldConstrainToRootBounds="False"> <Flyout x:Name="DateTimeFlyout" ShouldConstrainToRootBounds="False">
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="28" />
<RowDefinition Height="Auto" />
<RowDefinition Height="28" /> <RowDefinition Height="28" />
<RowDefinition Height="*" /> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
@@ -364,7 +366,45 @@
</DataTemplate> </DataTemplate>
</ListView.ItemTemplate> </ListView.ItemTemplate>
</ListView> </ListView>
<TextBlock x:Uid="CounterCheatSheet_Title"
Margin="0,10,0,0"
FontWeight="SemiBold" Grid.Row="2" />
<ListView Margin="-4,12,0,0"
IsItemClickEnabled="True"
ItemClick="DateTimeItemClick"
ItemsSource="{x:Bind CounterShortcuts}"
SelectionMode="None" Grid.Row="3">
<ListView.ItemTemplate>
<DataTemplate
x:DataType="local:PatternSnippet">
<Grid Margin="-10,0,0,0"
ColumnSpacing="8">
<Grid.ColumnDefinitions>
<ColumnDefinition
Width="Auto" />
<ColumnDefinition
Width="*" />
</Grid.ColumnDefinitions>
<Border Padding="8"
HorizontalAlignment="Left"
Background="{ThemeResource ButtonBackground}"
BorderBrush="{ThemeResource ButtonBorderBrush}"
BorderThickness="1"
CornerRadius="4">
<TextBlock
FontFamily="Consolas"
Foreground="{ThemeResource ButtonForeground}"
Text="{x:Bind Code}" />
</Border>
<TextBlock Grid.Column="1"
VerticalAlignment="Center"
FontSize="12"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Text="{x:Bind Description}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid> </Grid>
</Flyout> </Flyout>
</Button.Flyout> </Button.Flyout>

View File

@@ -196,6 +196,13 @@ namespace winrt::PowerRenameUI::implementation
m_dateTimeShortcuts.Append(winrt::make<PatternSnippet>(L"$ff", manager.MainResourceMap().GetValue(L"Resources/DateTimeCheatSheet_MilliSeconds2D").ValueAsString())); m_dateTimeShortcuts.Append(winrt::make<PatternSnippet>(L"$ff", manager.MainResourceMap().GetValue(L"Resources/DateTimeCheatSheet_MilliSeconds2D").ValueAsString()));
m_dateTimeShortcuts.Append(winrt::make<PatternSnippet>(L"$f", manager.MainResourceMap().GetValue(L"Resources/DateTimeCheatSheet_MilliSeconds1D").ValueAsString())); m_dateTimeShortcuts.Append(winrt::make<PatternSnippet>(L"$f", manager.MainResourceMap().GetValue(L"Resources/DateTimeCheatSheet_MilliSeconds1D").ValueAsString()));
m_CounterShortcuts = winrt::single_threaded_observable_vector<PowerRenameUI::PatternSnippet>();
m_CounterShortcuts.Append(winrt::make<PatternSnippet>(L"${}", manager.MainResourceMap().GetValue(L"Resources/CounterCheatSheet_Simple").ValueAsString()));
m_CounterShortcuts.Append(winrt::make<PatternSnippet>(L"${start=10}", manager.MainResourceMap().GetValue(L"Resources/CounterCheatSheet_Start").ValueAsString()));
m_CounterShortcuts.Append(winrt::make<PatternSnippet>(L"${increment=5}", manager.MainResourceMap().GetValue(L"Resources/CounterCheatSheet_Increment").ValueAsString()));
m_CounterShortcuts.Append(winrt::make<PatternSnippet>(L"${padding=8}", manager.MainResourceMap().GetValue(L"Resources/CounterCheatSheet_Padding").ValueAsString()));
m_CounterShortcuts.Append(winrt::make<PatternSnippet>(L"${increment=3,padding=4,start=900}", manager.MainResourceMap().GetValue(L"Resources/CounterCheatSheet_Complex").ValueAsString()));
InitializeComponent(); InitializeComponent();
listView_ExplorerItems().ApplyTemplate(); listView_ExplorerItems().ApplyTemplate();

View File

@@ -81,6 +81,8 @@ namespace winrt::PowerRenameUI::implementation
PowerRenameUI::ExplorerItemsSource ExplorerItems() { return m_explorerItems; } PowerRenameUI::ExplorerItemsSource ExplorerItems() { return m_explorerItems; }
winrt::Windows::Foundation::Collections::IObservableVector<PowerRenameUI::PatternSnippet> SearchRegExShortcuts() { return m_searchRegExShortcuts; } winrt::Windows::Foundation::Collections::IObservableVector<PowerRenameUI::PatternSnippet> SearchRegExShortcuts() { return m_searchRegExShortcuts; }
winrt::Windows::Foundation::Collections::IObservableVector<PowerRenameUI::PatternSnippet> DateTimeShortcuts() { return m_dateTimeShortcuts; } winrt::Windows::Foundation::Collections::IObservableVector<PowerRenameUI::PatternSnippet> DateTimeShortcuts() { return m_dateTimeShortcuts; }
winrt::Windows::Foundation::Collections::IObservableVector<PowerRenameUI::PatternSnippet> CounterShortcuts() { return m_CounterShortcuts; }
hstring OriginalCount(); hstring OriginalCount();
void OriginalCount(hstring value); void OriginalCount(hstring value);
hstring RenamedCount(); hstring RenamedCount();
@@ -100,6 +102,7 @@ namespace winrt::PowerRenameUI::implementation
PowerRenameUI::ExplorerItemsSource m_explorerItems; PowerRenameUI::ExplorerItemsSource m_explorerItems;
winrt::Windows::Foundation::Collections::IObservableVector<PowerRenameUI::PatternSnippet> m_searchRegExShortcuts; winrt::Windows::Foundation::Collections::IObservableVector<PowerRenameUI::PatternSnippet> m_searchRegExShortcuts;
winrt::Windows::Foundation::Collections::IObservableVector<PowerRenameUI::PatternSnippet> m_dateTimeShortcuts; winrt::Windows::Foundation::Collections::IObservableVector<PowerRenameUI::PatternSnippet> m_dateTimeShortcuts;
winrt::Windows::Foundation::Collections::IObservableVector<PowerRenameUI::PatternSnippet> m_CounterShortcuts;
// Used by PowerRenameManagerEvents // Used by PowerRenameManagerEvents
HRESULT OnRename(_In_ IPowerRenameItem* renameItem); HRESULT OnRename(_In_ IPowerRenameItem* renameItem);

View File

@@ -150,6 +150,24 @@
<data name="ReplaceBox.PlaceholderText" xml:space="preserve"> <data name="ReplaceBox.PlaceholderText" xml:space="preserve">
<value>Replace with</value> <value>Replace with</value>
</data> </data>
<data name="CounterCheatSheet_Title.Text" xml:space="preserve">
<value>Replace using advanced counter syntax.</value>
</data>
<data name="CounterCheatSheet_Simple" xml:space="preserve">
<value>A simple counter that you can use anywhere in a replace string.</value>
</data>
<data name="CounterCheatSheet_Start" xml:space="preserve">
<value>A counter with a customized start value.</value>
</data>
<data name="CounterCheatSheet_Increment" xml:space="preserve">
<value>A counter with a customized increment value.</value>
</data>
<data name="CounterCheatSheet_Padding" xml:space="preserve">
<value>A counter with a customized number of leading padding zeroes.</value>
</data>
<data name="CounterCheatSheet_Complex" xml:space="preserve">
<value>A counter showing multiple customized properties.</value>
</data>
<data name="DateTimeCheatSheet_Title.Text" xml:space="preserve"> <data name="DateTimeCheatSheet_Title.Text" xml:space="preserve">
<value>Replace using file creation date and time</value> <value>Replace using file creation date and time</value>
</data> </data>

View File

@@ -0,0 +1,46 @@
#include <pch.h>
#include "Enumerating.h"
#include <common\utils\string_utils.h>
std::vector<EnumOptions> parseEnumOptions(const std::wstring& replaceWith)
{
static const std::wregex enumStartRegex(LR"(start=(\d+))");
static const std::wregex enumIncrementRegex(LR"(increment=(-?\d+))");
static const std::wregex enumPaddingRegex(LR"(padding=(\d+))");
std::string buf;
std::vector<EnumOptions> options;
std::wregex enumGroupRegex(LR"(\$\{.*?\})");
for (std::wsregex_iterator i{ begin(replaceWith), end(replaceWith), enumGroupRegex }, end; i != end; ++i)
{
std::wsmatch match = *i;
std::wstring matchString = match.str();
EnumOptions option;
option.replaceStrSpan.offset = match.position();
option.replaceStrSpan.length = match.length();
std::wsmatch subMatch;
if (std::regex_search(matchString, subMatch, enumStartRegex))
{
buf = unwide(subMatch[1].str());
std::from_chars(buf.data(), buf.data() + buf.size(), option.start.emplace());
}
if (std::regex_search(matchString, subMatch, enumIncrementRegex))
{
buf = unwide(subMatch[1].str());
std::from_chars(buf.data(), buf.data() + buf.size(), option.increment.emplace());
}
if (std::regex_search(matchString, subMatch, enumPaddingRegex))
{
buf = unwide(subMatch[1].str());
std::from_chars(buf.data(), buf.data() + buf.size(), option.padding.emplace());
}
options.emplace_back(std::move(option));
}
return options;
}

View File

@@ -0,0 +1,55 @@
#pragma once
#include "pch.h"
struct EnumSpan
{
size_t offset = 0;
size_t length = 0;
};
struct EnumOptions
{
std::optional<int> start;
std::optional<int> increment;
std::optional<uint32_t> padding;
EnumSpan replaceStrSpan;
std::strong_ordering operator<=>(const EnumOptions& rhs) const noexcept
{
return std::make_tuple(start, increment, padding) <=> std::make_tuple(rhs.start, rhs.increment, rhs.padding);
}
bool operator==(const EnumOptions& rhs) const noexcept
{
return std::make_tuple(start, increment, padding) == std::make_tuple(rhs.start, rhs.increment, rhs.padding);
}
};
std::vector<EnumOptions> parseEnumOptions(const std::wstring& replaceWith);
struct Enumerator
{
inline Enumerator(EnumOptions options) :
start{ options.start.value_or(0) }, increment{ options.increment.value_or(1) }, padding{ options.padding.value_or(0) }, replaceStrSpan{ options.replaceStrSpan }
{
}
inline int32_t enumerate(const unsigned long index) const { return start + static_cast<int32_t>(index * increment); }
inline size_t printTo(wchar_t* buf, const size_t bufSize, const unsigned long index) const
{
const int32_t enumeratedIndex = enumerate(index);
wchar_t format[32];
swprintf_s(format, sizeof(format) / sizeof(wchar_t), L"%%0%ud", padding);
return swprintf_s(buf, bufSize, format, enumeratedIndex);
}
EnumSpan replaceStrSpan;
private:
int start;
int increment;
uint32_t padding;
};

View File

@@ -188,7 +188,7 @@ HRESULT GetTransformedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR sour
{ {
hr = StringCchCopy(result, cchMax, source); hr = StringCchCopy(result, cchMax, source);
} }
} }
else if (flags & Capitalized) else if (flags & Capitalized)
{ {
if (!(flags & ExtensionOnly)) if (!(flags & ExtensionOnly))
@@ -234,15 +234,13 @@ HRESULT GetTransformedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR sour
return hr; return hr;
} }
bool isFileTimeUsed(_In_ PCWSTR source) bool isFileTimeUsed(_In_ PCWSTR source)
{ {
bool used = false; bool used = false;
std::wstring patterns[] = { L"(([^\\$]|^)(\\$\\$)*)\\$Y", L"(([^\\$]|^)(\\$\\$)*)\\$M", L"(([^\\$]|^)(\\$\\$)*)\\$D", static const std::array patterns = { std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$Y" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$M" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$D" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$h" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$m" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$s" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$f" } };
L"(([^\\$]|^)(\\$\\$)*)\\$h", L"(([^\\$]|^)(\\$\\$)*)\\$m", L"(([^\\$]|^)(\\$\\$)*)\\$s", L"(([^\\$]|^)(\\$\\$)*)\\$f" }; for (size_t i = 0; !used && i < patterns.size(); i++)
size_t patternsLength = ARRAYSIZE(patterns);
for (size_t i = 0; !used && i < patternsLength; i++)
{ {
if (std::regex_search(source, std::wregex(patterns[i]))) if (std::regex_search(source, patterns[i]))
{ {
used = true; used = true;
} }
@@ -253,7 +251,7 @@ bool isFileTimeUsed(_In_ PCWSTR source)
HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SYSTEMTIME fileTime) HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SYSTEMTIME fileTime)
{ {
std::locale::global(std::locale("")); std::locale::global(std::locale(""));
HRESULT hr = E_INVALIDARG; HRESULT hr = E_INVALIDARG;
if (source && wcslen(source) > 0) if (source && wcslen(source) > 0)
{ {
std::wstring res(source); std::wstring res(source);
@@ -274,17 +272,17 @@ HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SY
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%d"), L"$01", (fileTime.wYear % 10)); StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%d"), L"$01", (fileTime.wYear % 10));
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$Y"), replaceTerm); res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$Y"), replaceTerm);
GetDateFormatEx(localeName, NULL, &fileTime, L"MMMM", formattedDate, MAX_PATH, NULL); GetDateFormatEx(localeName, NULL, &fileTime, L"MMMM", formattedDate, MAX_PATH, NULL);
formattedDate[0] = towupper(formattedDate[0]); formattedDate[0] = towupper(formattedDate[0]);
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%s"), L"$01", formattedDate); StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%s"), L"$01", formattedDate);
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$MMMM"), replaceTerm); res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$MMMM"), replaceTerm);
GetDateFormatEx(localeName, NULL, &fileTime, L"MMM", formattedDate, MAX_PATH, NULL); GetDateFormatEx(localeName, NULL, &fileTime, L"MMM", formattedDate, MAX_PATH, NULL);
formattedDate[0] = towupper(formattedDate[0]); formattedDate[0] = towupper(formattedDate[0]);
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%s"), L"$01", formattedDate); StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%s"), L"$01", formattedDate);
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$MMM"), replaceTerm); res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$MMM"), replaceTerm);
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%02d"), L"$01", fileTime.wMonth); StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%02d"), L"$01", fileTime.wMonth);
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$MM"), replaceTerm); res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$MM"), replaceTerm);
@@ -295,7 +293,7 @@ HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SY
formattedDate[0] = towupper(formattedDate[0]); formattedDate[0] = towupper(formattedDate[0]);
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%s"), L"$01", formattedDate); StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%s"), L"$01", formattedDate);
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$DDDD"), replaceTerm); res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$DDDD"), replaceTerm);
GetDateFormatEx(localeName, NULL, &fileTime, L"ddd", formattedDate, MAX_PATH, NULL); GetDateFormatEx(localeName, NULL, &fileTime, L"ddd", formattedDate, MAX_PATH, NULL);
formattedDate[0] = towupper(formattedDate[0]); formattedDate[0] = towupper(formattedDate[0]);
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%s"), L"$01", formattedDate); StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%s"), L"$01", formattedDate);
@@ -328,10 +326,10 @@ HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SY
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%03d"), L"$01", fileTime.wMilliseconds); StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%03d"), L"$01", fileTime.wMilliseconds);
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$fff"), replaceTerm); res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$fff"), replaceTerm);
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%02d"), L"$01", fileTime.wMilliseconds/10); StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%02d"), L"$01", fileTime.wMilliseconds / 10);
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$ff"), replaceTerm); res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$ff"), replaceTerm);
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%d"), L"$01", fileTime.wMilliseconds/100); StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%d"), L"$01", fileTime.wMilliseconds / 100);
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$f"), replaceTerm); res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$f"), replaceTerm);
hr = StringCchCopy(result, cchMax, res.c_str()); hr = StringCchCopy(result, cchMax, res.c_str());

View File

@@ -58,7 +58,7 @@ public:
IFACEMETHOD(PutFlags)(_In_ DWORD flags) = 0; IFACEMETHOD(PutFlags)(_In_ DWORD flags) = 0;
IFACEMETHOD(PutFileTime)(_In_ SYSTEMTIME fileTime) = 0; IFACEMETHOD(PutFileTime)(_In_ SYSTEMTIME fileTime) = 0;
IFACEMETHOD(ResetFileTime)() = 0; IFACEMETHOD(ResetFileTime)() = 0;
IFACEMETHOD(Replace)(_In_ PCWSTR source, _Outptr_ PWSTR* result) = 0; IFACEMETHOD(Replace)(_In_ PCWSTR source, _Outptr_ PWSTR* result, unsigned long& enumIndex) = 0;
}; };
interface __declspec(uuid("C7F59201-4DE1-4855-A3A2-26FC3279C8A5")) IPowerRenameItem : public IUnknown interface __declspec(uuid("C7F59201-4DE1-4855-A3A2-26FC3279C8A5")) IPowerRenameItem : public IUnknown

View File

@@ -31,6 +31,7 @@
</ClCompile> </ClCompile>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Enumerating.h" />
<ClInclude Include="Helpers.h" /> <ClInclude Include="Helpers.h" />
<ClInclude Include="MRUListHandler.h" /> <ClInclude Include="MRUListHandler.h" />
<ClInclude Include="PowerRenameEnum.h" /> <ClInclude Include="PowerRenameEnum.h" />
@@ -47,6 +48,7 @@
<ClInclude Include="trace.h" /> <ClInclude Include="trace.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Enumerating.cpp" />
<ClCompile Include="Helpers.cpp" /> <ClCompile Include="Helpers.cpp" />
<ClCompile Include="MRUListHandler.cpp" /> <ClCompile Include="MRUListHandler.cpp" />
<ClCompile Include="PowerRenameEnum.cpp" /> <ClCompile Include="PowerRenameEnum.cpp" />

View File

@@ -923,7 +923,7 @@ DWORD WINAPI CPowerRenameManager::s_regexWorkerThread(_In_ void* pv)
winrt::check_hresult(pwtd->spsrm->GetRenameRegEx(&spRenameRegEx)); winrt::check_hresult(pwtd->spsrm->GetRenameRegEx(&spRenameRegEx));
UINT itemCount = 0; UINT itemCount = 0;
unsigned long itemEnumIndex = 1; unsigned long itemEnumIndex = 0;
winrt::check_hresult(pwtd->spsrm->GetItemCount(&itemCount)); winrt::check_hresult(pwtd->spsrm->GetItemCount(&itemCount));
for (UINT u = 0; u < itemCount; u++) for (UINT u = 0; u < itemCount; u++)

View File

@@ -1,5 +1,6 @@
#include "pch.h" #include "pch.h"
#include "PowerRenameRegEx.h" #include "PowerRenameRegEx.h"
#include "Enumerating.h"
#include "Settings.h" #include "Settings.h"
#include <regex> #include <regex>
#include <string> #include <string>
@@ -7,15 +8,17 @@
#include <boost/regex.hpp> #include <boost/regex.hpp>
#include <helpers.h> #include <helpers.h>
using namespace std; using std::conditional_t;
using std::regex_error; using std::regex_error;
IFACEMETHODIMP_(ULONG) CPowerRenameRegEx::AddRef() IFACEMETHODIMP_(ULONG)
CPowerRenameRegEx::AddRef()
{ {
return InterlockedIncrement(&m_refCount); return InterlockedIncrement(&m_refCount);
} }
IFACEMETHODIMP_(ULONG) CPowerRenameRegEx::Release() IFACEMETHODIMP_(ULONG)
CPowerRenameRegEx::Release()
{ {
long refCount = InterlockedDecrement(&m_refCount); long refCount = InterlockedDecrement(&m_refCount);
@@ -127,6 +130,26 @@ IFACEMETHODIMP CPowerRenameRegEx::GetReplaceTerm(_Outptr_ PWSTR* replaceTerm)
return hr; return hr;
} }
HRESULT CPowerRenameRegEx::_OnEnumerateItemsChanged()
{
m_enumerators.clear();
const auto options = parseEnumOptions(m_RawReplaceTerm);
for (const auto e : options)
m_enumerators.emplace_back(e);
m_replaceWithEnumeratorOffsets.clear();
std::wstring replaceWith{ m_RawReplaceTerm };
// Remove counter expressions and calculate their offsets in replaceWith string.
int32_t offset = 0;
for (const auto& e : options)
{
replaceWith.erase(e.replaceStrSpan.offset + offset, e.replaceStrSpan.length);
m_replaceWithEnumeratorOffsets.push_back(offset);
offset -= static_cast<int32_t>(e.replaceStrSpan.length);
}
return SHStrDup(replaceWith.data(), &m_replaceTerm);
}
IFACEMETHODIMP CPowerRenameRegEx::PutReplaceTerm(_In_ PCWSTR replaceTerm, bool forceRenaming) IFACEMETHODIMP CPowerRenameRegEx::PutReplaceTerm(_In_ PCWSTR replaceTerm, bool forceRenaming)
{ {
bool changed = false || forceRenaming; bool changed = false || forceRenaming;
@@ -134,11 +157,16 @@ IFACEMETHODIMP CPowerRenameRegEx::PutReplaceTerm(_In_ PCWSTR replaceTerm, bool f
if (replaceTerm) if (replaceTerm)
{ {
CSRWExclusiveAutoLock lock(&m_lock); CSRWExclusiveAutoLock lock(&m_lock);
if (m_replaceTerm == nullptr || lstrcmp(replaceTerm, m_replaceTerm) != 0) if (m_replaceTerm == nullptr || lstrcmp(replaceTerm, m_RawReplaceTerm.c_str()) != 0)
{ {
changed = true; changed = true;
CoTaskMemFree(m_replaceTerm); CoTaskMemFree(m_replaceTerm);
hr = SHStrDup(replaceTerm, &m_replaceTerm); m_RawReplaceTerm = replaceTerm;
if (m_flags & EnumerateItems)
hr = _OnEnumerateItemsChanged();
else
hr = SHStrDup(replaceTerm, &m_replaceTerm);
} }
} }
@@ -160,7 +188,20 @@ IFACEMETHODIMP CPowerRenameRegEx::PutFlags(_In_ DWORD flags)
{ {
if (m_flags != flags) if (m_flags != flags)
{ {
const bool newEnumerate = flags & EnumerateItems;
const bool refreshReplaceTerm = !!(m_flags & EnumerateItems) != newEnumerate;
m_flags = flags; m_flags = flags;
if (refreshReplaceTerm)
{
CSRWExclusiveAutoLock lock(&m_lock);
if (newEnumerate)
_OnEnumerateItemsChanged();
else
{
CoTaskMemFree(m_replaceTerm);
SHStrDup(m_RawReplaceTerm.c_str(), &m_replaceTerm);
}
}
_OnFlagsChanged(); _OnFlagsChanged();
} }
return S_OK; return S_OK;
@@ -202,7 +243,7 @@ HRESULT CPowerRenameRegEx::s_CreateInstance(_Outptr_ IPowerRenameRegEx** renameR
{ {
*renameRegEx = nullptr; *renameRegEx = nullptr;
CPowerRenameRegEx *newRenameRegEx = new CPowerRenameRegEx(); CPowerRenameRegEx* newRenameRegEx = new CPowerRenameRegEx();
HRESULT hr = E_OUTOFMEMORY; HRESULT hr = E_OUTOFMEMORY;
if (newRenameRegEx) if (newRenameRegEx)
{ {
@@ -228,7 +269,20 @@ CPowerRenameRegEx::~CPowerRenameRegEx()
CoTaskMemFree(m_replaceTerm); CoTaskMemFree(m_replaceTerm);
} }
HRESULT CPowerRenameRegEx::Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result) template<bool Std, class Regex = conditional_t<Std, std::wregex, boost::wregex>, class Options = decltype(Regex::icase)>
static std::wstring RegexReplaceEx(const std::wstring& source, const std::wstring& searchTerm, const std::wstring& replaceTerm, const bool matchAll, const bool caseInsensitive)
{
Regex pattern(searchTerm, Options::ECMAScript | (caseInsensitive ? Options::icase : Options{}));
using Flags = conditional_t<Std, std::regex_constants::match_flag_type, boost::regex_constants::match_flags>;
const auto flags = matchAll ? Flags::match_default : Flags::format_first_only;
return regex_replace(source, pattern, replaceTerm, flags);
}
static constexpr std::array RegexReplaceDispatch = { RegexReplaceEx<true>, RegexReplaceEx<false> };
HRESULT CPowerRenameRegEx::Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result, unsigned long& enumIndex)
{ {
*result = nullptr; *result = nullptr;
@@ -238,7 +292,7 @@ HRESULT CPowerRenameRegEx::Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result)
{ {
return hr; return hr;
} }
wstring res = source; std::wstring res = source;
try try
{ {
// TODO: creating the regex could be costly. May want to cache this. // TODO: creating the regex could be costly. May want to cache this.
@@ -250,47 +304,49 @@ HRESULT CPowerRenameRegEx::Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result)
fileTimeErrorOccurred = true; fileTimeErrorOccurred = true;
} }
std::wstring sourceToUse(source); std::wstring sourceToUse;
std::wstring originalSource;
sourceToUse.reserve(MAX_PATH);
originalSource.reserve(MAX_PATH);
sourceToUse = source;
originalSource = sourceToUse;
std::wstring searchTerm(m_searchTerm); std::wstring searchTerm(m_searchTerm);
std::wstring replaceTerm(L""); std::wstring replaceTerm;
if (m_useFileTime && !fileTimeErrorOccurred) if (m_useFileTime && !fileTimeErrorOccurred)
{ {
replaceTerm = wstring(newReplaceTerm); replaceTerm = newReplaceTerm;
} }
else if (m_replaceTerm) else if (m_replaceTerm)
{ {
replaceTerm = wstring(m_replaceTerm); replaceTerm = m_replaceTerm;
} }
replaceTerm = regex_replace(replaceTerm, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$[0]"), L"$1$$$0"); static const std::wregex zeroGroupRegex(L"(([^\\$]|^)(\\$\\$)*)\\$[0]");
replaceTerm = regex_replace(replaceTerm, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$([1-9])"), L"$1$0$4"); static const std::wregex otherGroupsRegex(L"(([^\\$]|^)(\\$\\$)*)\\$([1-9])");
if (m_flags & EnumerateItems)
{
std::array<wchar_t, MAX_PATH> buffer;
int32_t offset = 0;
for (size_t ei = 0; ei < m_enumerators.size(); ++ei)
{
const auto& e = m_enumerators[ei];
const auto replacementLength = static_cast<int32_t>(e.printTo(buffer.data(), buffer.size(), enumIndex));
replaceTerm.insert(e.replaceStrSpan.offset + offset + m_replaceWithEnumeratorOffsets[ei], buffer.data());
offset += replacementLength;
}
}
bool replacedSomething = false;
if (m_flags & UseRegularExpressions) if (m_flags & UseRegularExpressions)
{ {
if (_useBoostLib) replaceTerm = regex_replace(replaceTerm, zeroGroupRegex, L"$1$$$0");
{ replaceTerm = regex_replace(replaceTerm, otherGroupsRegex, L"$1$0$4");
boost::wregex pattern(m_searchTerm, (!(m_flags & CaseSensitive)) ? boost::regex::icase | boost::regex::ECMAScript : boost::regex::ECMAScript);
if (m_flags & MatchAllOccurrences) res = RegexReplaceDispatch[_useBoostLib](source, m_searchTerm, replaceTerm, m_flags & MatchAllOccurrences, !(m_flags & CaseSensitive));
{ replacedSomething = originalSource != res;
res = boost::regex_replace(wstring(source), pattern, replaceTerm);
}
else
{
res = boost::regex_replace(wstring(source), pattern, replaceTerm, boost::regex_constants::format_first_only);
}
}
else
{
std::wregex pattern(m_searchTerm, (!(m_flags & CaseSensitive)) ? regex_constants::icase | regex_constants::ECMAScript : regex_constants::ECMAScript);
if (m_flags & MatchAllOccurrences)
{
res = regex_replace(wstring(source), pattern, replaceTerm);
}
else
{
res = regex_replace(wstring(source), pattern, replaceTerm, regex_constants::format_first_only);
}
}
} }
else else
{ {
@@ -303,16 +359,17 @@ HRESULT CPowerRenameRegEx::Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result)
{ {
res = sourceToUse.replace(pos, searchTerm.length(), replaceTerm); res = sourceToUse.replace(pos, searchTerm.length(), replaceTerm);
pos += replaceTerm.length(); pos += replaceTerm.length();
replacedSomething = true;
} }
if (!(m_flags & MatchAllOccurrences)) if (!(m_flags & MatchAllOccurrences))
{ {
break; break;
} }
} while (pos != std::string::npos); } while (pos != std::string::npos);
} }
hr = SHStrDup(res.c_str(), result); hr = SHStrDup(res.c_str(), result);
if (replacedSomething)
enumIndex++;
} }
catch (regex_error e) catch (regex_error e)
{ {

View File

@@ -1,9 +1,8 @@
#pragma once #pragma once
#include "pch.h" #include "pch.h"
#include <vector>
#include <string>
#include "srwlock.h" #include "srwlock.h"
#include "Enumerating.h"
#include "PowerRenameInterfaces.h" #include "PowerRenameInterfaces.h"
#define DEFAULT_FLAGS 0 #define DEFAULT_FLAGS 0
@@ -12,7 +11,7 @@ class CPowerRenameRegEx : public IPowerRenameRegEx
{ {
public: public:
// IUnknown // IUnknown
IFACEMETHODIMP QueryInterface(_In_ REFIID iid, _Outptr_ void** resultInterface); IFACEMETHODIMP QueryInterface(_In_ REFIID iid, _Outptr_ void** resultInterface);
IFACEMETHODIMP_(ULONG) AddRef(); IFACEMETHODIMP_(ULONG) AddRef();
IFACEMETHODIMP_(ULONG) Release(); IFACEMETHODIMP_(ULONG) Release();
@@ -27,9 +26,9 @@ public:
IFACEMETHODIMP PutFlags(_In_ DWORD flags); IFACEMETHODIMP PutFlags(_In_ DWORD flags);
IFACEMETHODIMP PutFileTime(_In_ SYSTEMTIME fileTime); IFACEMETHODIMP PutFileTime(_In_ SYSTEMTIME fileTime);
IFACEMETHODIMP ResetFileTime(); IFACEMETHODIMP ResetFileTime();
IFACEMETHODIMP Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result); IFACEMETHODIMP Replace(_In_ PCWSTR source, _Outptr_ PWSTR* result, unsigned long& enumIndex);
static HRESULT s_CreateInstance(_Outptr_ IPowerRenameRegEx **renameRegEx); static HRESULT s_CreateInstance(_Outptr_ IPowerRenameRegEx** renameRegEx);
protected: protected:
CPowerRenameRegEx(); CPowerRenameRegEx();
@@ -39,6 +38,7 @@ protected:
void _OnReplaceTermChanged(); void _OnReplaceTermChanged();
void _OnFlagsChanged(); void _OnFlagsChanged();
void _OnFileTimeChanged(); void _OnFileTimeChanged();
HRESULT _OnEnumerateItemsChanged();
size_t _Find(std::wstring data, std::wstring toSearch, bool caseInsensitive, size_t pos); size_t _Find(std::wstring data, std::wstring toSearch, bool caseInsensitive, size_t pos);
@@ -46,8 +46,9 @@ protected:
DWORD m_flags = DEFAULT_FLAGS; DWORD m_flags = DEFAULT_FLAGS;
PWSTR m_searchTerm = nullptr; PWSTR m_searchTerm = nullptr;
PWSTR m_replaceTerm = nullptr; PWSTR m_replaceTerm = nullptr;
std::wstring m_RawReplaceTerm;
SYSTEMTIME m_fileTime = {0}; SYSTEMTIME m_fileTime = { 0 };
bool m_useFileTime = false; bool m_useFileTime = false;
CSRWLock m_lock; CSRWLock m_lock;
@@ -55,6 +56,9 @@ protected:
DWORD m_cookie = 0; DWORD m_cookie = 0;
std::vector<Enumerator> m_enumerators;
std::vector<int32_t> m_replaceWithEnumeratorOffsets;
struct RENAME_REGEX_EVENT struct RENAME_REGEX_EVENT
{ {
IPowerRenameRegExEvents* pEvents; IPowerRenameRegExEvents* pEvents;

View File

@@ -86,7 +86,7 @@ bool DoRename(CComPtr<IPowerRenameRegEx>& spRenameRegEx, unsigned long& itemEnum
// Failure here means we didn't match anything or had nothing to match // Failure here means we didn't match anything or had nothing to match
// Call put_newName with null in that case to reset it // Call put_newName with null in that case to reset it
winrt::check_hresult(spRenameRegEx->Replace(sourceName, &newName)); winrt::check_hresult(spRenameRegEx->Replace(sourceName, &newName, itemEnumIndex));
if (useFileTime) if (useFileTime)
{ {
@@ -166,17 +166,6 @@ bool DoRename(CComPtr<IPowerRenameRegEx>& spRenameRegEx, unsigned long& itemEnum
newNameToUse = nullptr; newNameToUse = nullptr;
} }
wchar_t uniqueName[MAX_PATH] = { 0 };
if (newNameToUse != nullptr && (flags & EnumerateItems))
{
unsigned long countUsed = 0;
if (GetEnumeratedFileName(uniqueName, ARRAYSIZE(uniqueName), newNameToUse, nullptr, itemEnumIndex, &countUsed))
{
newNameToUse = uniqueName;
}
itemEnumIndex++;
}
spItem->PutStatus(PowerRenameItemRenameStatus::ShouldRename); spItem->PutStatus(PowerRenameItemRenameStatus::ShouldRename);
if (newNameToUse != nullptr) if (newNameToUse != nullptr)
{ {

View File

@@ -21,6 +21,12 @@
#include <shlwapi.h> #include <shlwapi.h>
#include <ShlObj_core.h> #include <ShlObj_core.h>
#include <filesystem> #include <filesystem>
#include <compare>
#include <regex>
#include <vector>
#include <variant>
#include <charconv>
#include <string>
#include <ProjectTelemetry.h> #include <ProjectTelemetry.h>

View File

@@ -0,0 +1,472 @@
//#undef TESTS_PARTIAL // Uncomment temporarily to make intellisense work in this file.
#ifndef TESTS_PARTIAL
#include "CppUnitTestInclude.h"
#include "powerrename/lib/Settings.h"
#include <PowerRenameInterfaces.h>
#include <PowerRenameRegEx.h>
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace PowerRenameRegExTests
{
TEST_CLASS (SimpleTests)
{
public:
#endif
struct SearchReplaceExpected
{
PCWSTR search;
PCWSTR replace;
PCWSTR test;
PCWSTR expected;
};
TEST_METHOD (GeneralReplaceTest)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(L"foo") == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(L"big") == S_OK);
unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result, index) == S_OK);
Assert::AreEqual(L"bigbar", result);
CoTaskMemFree(result);
}
TEST_METHOD (ReplaceNoMatch)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(L"notfound") == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(L"big") == S_OK);
unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result, index) == S_OK);
Assert::AreEqual(L"foobar", result);
CoTaskMemFree(result);
}
TEST_METHOD (ReplaceNoSearchOrReplaceTerm)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
PWSTR result = nullptr;
unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result, index) == S_OK);
Assert::IsTrue(result == nullptr);
CoTaskMemFree(result);
}
TEST_METHOD (ReplaceNoReplaceTerm)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(L"foo") == S_OK);
unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result, index) == S_OK);
Assert::AreEqual(L"bar", result);
CoTaskMemFree(result);
}
TEST_METHOD (ReplaceEmptyStringReplaceTerm)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(L"foo") == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(L"") == S_OK);
unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result, index) == S_OK);
Assert::AreEqual(L"bar", result);
CoTaskMemFree(result);
}
TEST_METHOD (VerifyDefaultFlags)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = 0;
Assert::IsTrue(renameRegEx->GetFlags(&flags) == S_OK);
Assert::IsTrue(flags == 0);
}
TEST_METHOD (VerifyCaseSensitiveSearch)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = CaseSensitive;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
SearchReplaceExpected sreTable[] = {
{ L"Foo", L"Foo", L"FooBar", L"FooBar" },
{ L"Foo", L"boo", L"FooBar", L"booBar" },
{ L"Foo", L"boo", L"foobar", L"foobar" },
{ L"123", L"654", L"123456", L"654456" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result, index) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD (VerifyReplaceFirstOnly)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = 0;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
SearchReplaceExpected sreTable[] = {
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AABBA" },
{ L"B", L"BBB", L"ABABAB", L"ABBBABAB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result, index) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD (VerifyReplaceAll)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = MatchAllOccurrences;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
SearchReplaceExpected sreTable[] = {
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AAAAA" },
{ L"B", L"BBB", L"ABABAB", L"ABBBABBBABBB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result, index) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD (VerifyReplaceAllCaseInsensitive)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = MatchAllOccurrences | CaseSensitive;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
SearchReplaceExpected sreTable[] = {
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AAAAA" },
{ L"B", L"BBB", L"ABABAB", L"ABBBABBBABBB" },
{ L"b", L"BBB", L"AbABAb", L"ABBBABABBB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result, index) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD (VerifyReplaceFirstOnlyUseRegEx)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = UseRegularExpressions;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
SearchReplaceExpected sreTable[] = {
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AABBA" },
{ L"B", L"BBB", L"ABABAB", L"ABBBABAB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result, index) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD (VerifyReplaceAllUseRegEx)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = MatchAllOccurrences | UseRegularExpressions;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
SearchReplaceExpected sreTable[] = {
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AAAAA" },
{ L"B", L"BBB", L"ABABAB", L"ABBBABBBABBB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result, index) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD (VerifyReplaceAllUseRegExCaseSensitive)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = MatchAllOccurrences | UseRegularExpressions | CaseSensitive;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
SearchReplaceExpected sreTable[] = {
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AAAAA" },
{ L"b", L"BBB", L"AbABAb", L"ABBBABABBB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result, index) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
void VerifyReplaceFirstWildcard(SearchReplaceExpected sreTable[], int tableSize, DWORD flags)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
for (int i = 0; i < tableSize; i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result, index) == S_OK);
Assert::AreEqual(sreTable[i].expected, result);
CoTaskMemFree(result);
}
}
TEST_METHOD (VerifyReplaceFirstWildCardUseRegex)
{
SearchReplaceExpected sreTable[] = {
//search, replace, test, result
{ L".*", L"Foo", L"AAAAAA", L"Foo" },
};
VerifyReplaceFirstWildcard(sreTable, ARRAYSIZE(sreTable), UseRegularExpressions);
}
TEST_METHOD (VerifyReplaceFirstWildCardMatchAllOccurrences)
{
SearchReplaceExpected sreTable[] = {
//search, replace, test, result
{ L".*", L"Foo", L"AAAAAA", L"AAAAAA" },
{ L".*", L"Foo", L".*", L"Foo" },
{ L".*", L"Foo", L".*Bar.*", L"FooBarFoo" },
};
VerifyReplaceFirstWildcard(sreTable, ARRAYSIZE(sreTable), MatchAllOccurrences);
}
TEST_METHOD (VerifyReplaceFirstWildNoFlags)
{
SearchReplaceExpected sreTable[] = {
//search, replace, test, result
{ L".*", L"Foo", L"AAAAAA", L"AAAAAA" },
{ L".*", L"Foo", L".*", L"Foo" },
};
VerifyReplaceFirstWildcard(sreTable, ARRAYSIZE(sreTable), 0);
}
TEST_METHOD (VerifyEventsFire)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
CMockPowerRenameRegExEvents* mockEvents = new CMockPowerRenameRegExEvents();
CComPtr<IPowerRenameRegExEvents> regExEvents;
Assert::IsTrue(mockEvents->QueryInterface(IID_PPV_ARGS(&regExEvents)) == S_OK);
DWORD cookie = 0;
Assert::IsTrue(renameRegEx->Advise(regExEvents, &cookie) == S_OK);
DWORD flags = MatchAllOccurrences | UseRegularExpressions | CaseSensitive;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
Assert::IsTrue(renameRegEx->PutSearchTerm(L"FOO") == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(L"BAR") == S_OK);
Assert::IsTrue(renameRegEx->PutFileTime(SYSTEMTIME{ 0 }) == S_OK);
Assert::IsTrue(renameRegEx->ResetFileTime() == S_OK);
Assert::IsTrue(lstrcmpi(L"FOO", mockEvents->m_searchTerm) == 0);
Assert::IsTrue(lstrcmpi(L"BAR", mockEvents->m_replaceTerm) == 0);
Assert::IsTrue(flags == mockEvents->m_flags);
Assert::IsTrue(renameRegEx->UnAdvise(cookie) == S_OK);
mockEvents->Release();
}
TEST_METHOD (VerifySimpleCounterNoRegex)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = EnumerateItems;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(L"bar") == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(L"$1bar_${}") == S_OK);
unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result, index) == S_OK);
Assert::AreEqual(L"foo$1bar_0", result);
CoTaskMemFree(result);
}
TEST_METHOD (VerifySimpleCounterNoEnum)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = UseRegularExpressions;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(L"bar") == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(L"$1bar_${}") == S_OK);
unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result, index) == S_OK);
Assert::AreEqual(L"foobar_${}", result);
CoTaskMemFree(result);
}
TEST_METHOD (VerifySimpleCounter)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = EnumerateItems | UseRegularExpressions;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(L"bar") == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(L"bar_${}") == S_OK);
unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result, index) == S_OK);
Assert::AreEqual(L"foobar_0", result);
CoTaskMemFree(result);
}
TEST_METHOD (VerifyMultipleCounters)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = EnumerateItems | UseRegularExpressions;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
Assert::IsTrue(renameRegEx->PutSearchTerm(L"bar") == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(L"_${}_bar_${}") == S_OK);
unsigned long index = {};
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result, index) == S_OK);
Assert::AreEqual(L"foo_0_bar_0", result);
CoTaskMemFree(result);
}
TEST_METHOD (VerifyCounterIncrementCustomization)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = EnumerateItems | UseRegularExpressions;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
Assert::IsTrue(renameRegEx->PutSearchTerm(L"bar") == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(L"bar_${increment=10}") == S_OK);
unsigned long index = 1;
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result, index) == S_OK);
Assert::AreEqual(L"foobar_10", result);
Assert::AreEqual<unsigned long>(index, 2);
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result, index) == S_OK);
Assert::AreEqual(L"foobar_20", result);
Assert::AreEqual<unsigned long>(index, 3);
CoTaskMemFree(result);
}
TEST_METHOD (VerifyCounterStartCustomization)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = EnumerateItems | UseRegularExpressions;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
Assert::IsTrue(renameRegEx->PutSearchTerm(L"bar") == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(L"bar_${start=1000}") == S_OK);
unsigned long index = 5;
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result, index) == S_OK);
Assert::AreEqual(L"foobar_1005", result);
CoTaskMemFree(result);
}
TEST_METHOD (VerifyCounterPaddingCustomization)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = EnumerateItems | UseRegularExpressions;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
Assert::IsTrue(renameRegEx->PutSearchTerm(L"bar") == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(L"bar_${padding=5}") == S_OK);
unsigned long index = 204;
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result, index) == S_OK);
Assert::AreEqual(L"foobar_00204", result);
CoTaskMemFree(result);
}
TEST_METHOD (VerifyCounterAllCustomizations)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = EnumerateItems | UseRegularExpressions;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
Assert::IsTrue(renameRegEx->PutSearchTerm(L"bar") == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(L"bar_${increment=7,start=993,padding=5}") == S_OK);
unsigned long index = 12;
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result, index) == S_OK);
Assert::AreEqual(L"foobar_01077", result);
CoTaskMemFree(result);
}
#ifndef TESTS_PARTIAL
};
}
#endif

View File

@@ -0,0 +1,8 @@
#pragma once
// Headers for CppUnitTest
// Suppressing 26466 - Don't use static_cast downcasts - in CppUnitTest.h
#pragma warning(push)
#pragma warning(disable : 26466)
#include "CppUnitTest.h"
#pragma warning(pop)

View File

@@ -38,6 +38,7 @@
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="CppUnitTestInclude.h" />
<ClInclude Include="MockPowerRenameItem.h" /> <ClInclude Include="MockPowerRenameItem.h" />
<ClInclude Include="MockPowerRenameManagerEvents.h" /> <ClInclude Include="MockPowerRenameManagerEvents.h" />
<ClInclude Include="MockPowerRenameRegExEvents.h" /> <ClInclude Include="MockPowerRenameRegExEvents.h" />
@@ -45,6 +46,7 @@
<ClInclude Include="resource.h" /> <ClInclude Include="resource.h" />
<ClInclude Include="targetver.h" /> <ClInclude Include="targetver.h" />
<ClInclude Include="TestFileHelper.h" /> <ClInclude Include="TestFileHelper.h" />
<ClInclude Include="CommonRegExTests.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="MockPowerRenameItem.cpp" /> <ClCompile Include="MockPowerRenameItem.cpp" />

View File

@@ -17,9 +17,11 @@
<ClInclude Include="pch.h" /> <ClInclude Include="pch.h" />
<ClInclude Include="targetver.h" /> <ClInclude Include="targetver.h" />
<ClInclude Include="TestFileHelper.h" /> <ClInclude Include="TestFileHelper.h" />
<ClInclude Include="CommonRegExTests.h" />
<ClInclude Include="resource.h"> <ClInclude Include="resource.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="CppUnitTestInclude.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Filter Include="Resource Files"> <Filter Include="Resource Files">

View File

@@ -8,14 +8,6 @@ using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace PowerRenameRegExBoostTests namespace PowerRenameRegExBoostTests
{ {
struct SearchReplaceExpected
{
PCWSTR search;
PCWSTR replace;
PCWSTR test;
PCWSTR expected;
};
TEST_CLASS(SimpleTests) TEST_CLASS(SimpleTests)
{ {
public: public:
@@ -29,241 +21,8 @@ TEST_CLASS_CLEANUP(ClassCleanup)
CSettingsInstance().SetUseBoostLib(false); CSettingsInstance().SetUseBoostLib(false);
} }
TEST_METHOD(GeneralReplaceTest) #define TESTS_PARTIAL
{ #include "CommonRegExTests.h"
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(L"foo") == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(L"big") == S_OK);
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result) == S_OK);
Assert::IsTrue(wcscmp(result, L"bigbar") == 0);
CoTaskMemFree(result);
}
TEST_METHOD(ReplaceNoMatch)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(L"notfound") == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(L"big") == S_OK);
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result) == S_OK);
Assert::IsTrue(wcscmp(result, L"foobar") == 0);
CoTaskMemFree(result);
}
TEST_METHOD(ReplaceNoSearchOrReplaceTerm)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result) == S_OK);
Assert::IsTrue(result == nullptr);
CoTaskMemFree(result);
}
TEST_METHOD(ReplaceNoReplaceTerm)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(L"foo") == S_OK);
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result) == S_OK);
Assert::IsTrue(wcscmp(result, L"bar") == 0);
CoTaskMemFree(result);
}
TEST_METHOD(ReplaceEmptyStringReplaceTerm)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(L"foo") == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(L"") == S_OK);
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result) == S_OK);
Assert::IsTrue(wcscmp(result, L"bar") == 0);
CoTaskMemFree(result);
}
TEST_METHOD(VerifyDefaultFlags)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = 0;
Assert::IsTrue(renameRegEx->GetFlags(&flags) == S_OK);
Assert::IsTrue(flags == 0);
}
TEST_METHOD(VerifyCaseSensitiveSearch)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = CaseSensitive;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
SearchReplaceExpected sreTable[] = {
{ L"Foo", L"Foo", L"FooBar", L"FooBar" },
{ L"Foo", L"boo", L"FooBar", L"booBar" },
{ L"Foo", L"boo", L"foobar", L"foobar" },
{ L"123", L"654", L"123456", L"654456" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyReplaceFirstOnly)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = 0;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
SearchReplaceExpected sreTable[] = {
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AABBA" },
{ L"B", L"BBB", L"ABABAB", L"ABBBABAB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyReplaceAll)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = MatchAllOccurrences;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
SearchReplaceExpected sreTable[] = {
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AAAAA" },
{ L"B", L"BBB", L"ABABAB", L"ABBBABBBABBB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyReplaceAllCaseInsensitive)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = MatchAllOccurrences | CaseSensitive;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
SearchReplaceExpected sreTable[] = {
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AAAAA" },
{ L"B", L"BBB", L"ABABAB", L"ABBBABBBABBB" },
{ L"b", L"BBB", L"AbABAb", L"ABBBABABBB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyReplaceFirstOnlyUseRegEx)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = UseRegularExpressions;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
SearchReplaceExpected sreTable[] = {
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AABBA" },
{ L"B", L"BBB", L"ABABAB", L"ABBBABAB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyReplaceAllUseRegEx)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = MatchAllOccurrences | UseRegularExpressions;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
SearchReplaceExpected sreTable[] = {
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AAAAA" },
{ L"B", L"BBB", L"ABABAB", L"ABBBABBBABBB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyReplaceAllUseRegExCaseSensitive)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = MatchAllOccurrences | UseRegularExpressions | CaseSensitive;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
SearchReplaceExpected sreTable[] = {
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AAAAA" },
{ L"b", L"BBB", L"AbABAb", L"ABBBABABBB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyMatchAllWildcardUseRegEx) TEST_METHOD(VerifyMatchAllWildcardUseRegEx)
{ {
@@ -284,38 +43,13 @@ TEST_METHOD(VerifyMatchAllWildcardUseRegEx)
PWSTR result = nullptr; PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK); Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK); Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK); unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result, index) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0); Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result); CoTaskMemFree(result);
} }
} }
void VerifyReplaceFirstWildcard(SearchReplaceExpected sreTable[], int tableSize, DWORD flags)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
for (int i = 0; i < tableSize; i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::AreEqual(sreTable[i].expected, result);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyReplaceFirstWildCardUseRegex)
{
SearchReplaceExpected sreTable[] = {
//search, replace, test, result
{ L".*", L"Foo", L"AAAAAA", L"Foo" },
};
VerifyReplaceFirstWildcard(sreTable, ARRAYSIZE(sreTable), UseRegularExpressions);
}
TEST_METHOD(VerifyReplaceFirstWildCardUseRegexMatchAllOccurrences) TEST_METHOD(VerifyReplaceFirstWildCardUseRegexMatchAllOccurrences)
{ {
// This differs from the Standard Library: .* has two matches (all and nothing). // This differs from the Standard Library: .* has two matches (all and nothing).
@@ -327,27 +61,6 @@ TEST_METHOD(VerifyReplaceFirstWildCardUseRegexMatchAllOccurrences)
VerifyReplaceFirstWildcard(sreTable, ARRAYSIZE(sreTable), UseRegularExpressions | MatchAllOccurrences); VerifyReplaceFirstWildcard(sreTable, ARRAYSIZE(sreTable), UseRegularExpressions | MatchAllOccurrences);
} }
TEST_METHOD(VerifyReplaceFirstWildCardMatchAllOccurrences)
{
SearchReplaceExpected sreTable[] = {
//search, replace, test, result
{ L".*", L"Foo", L"AAAAAA", L"AAAAAA" },
{ L".*", L"Foo", L".*", L"Foo" },
{ L".*", L"Foo", L".*Bar.*", L"FooBarFoo" },
};
VerifyReplaceFirstWildcard(sreTable, ARRAYSIZE(sreTable), MatchAllOccurrences);
}
TEST_METHOD(VerifyReplaceFirstWildNoFlags)
{
SearchReplaceExpected sreTable[] = {
//search, replace, test, result
{ L".*", L"Foo", L"AAAAAA", L"AAAAAA" },
{ L".*", L"Foo", L".*", L"Foo" },
};
VerifyReplaceFirstWildcard(sreTable, ARRAYSIZE(sreTable), 0);
}
TEST_METHOD(VerifyHandleCapturingGroups) TEST_METHOD(VerifyHandleCapturingGroups)
{ {
// This differs from the Standard Library: Boost does not recognize $123 as $1 and "23". // This differs from the Standard Library: Boost does not recognize $123 as $1 and "23".
@@ -380,7 +93,8 @@ TEST_METHOD(VerifyHandleCapturingGroups)
PWSTR result = nullptr; PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK); Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK); Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK); unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result, index) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0); Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result); CoTaskMemFree(result);
} }
@@ -407,32 +121,11 @@ TEST_METHOD(VerifyLookbehind)
PWSTR result = nullptr; PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK); Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK); Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK); unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result, index) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0); Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result); CoTaskMemFree(result);
} }
} }
TEST_METHOD(VerifyEventsFire)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
CMockPowerRenameRegExEvents* mockEvents = new CMockPowerRenameRegExEvents();
CComPtr<IPowerRenameRegExEvents> regExEvents;
Assert::IsTrue(mockEvents->QueryInterface(IID_PPV_ARGS(&regExEvents)) == S_OK);
DWORD cookie = 0;
Assert::IsTrue(renameRegEx->Advise(regExEvents, &cookie) == S_OK);
DWORD flags = MatchAllOccurrences | UseRegularExpressions | CaseSensitive;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
Assert::IsTrue(renameRegEx->PutSearchTerm(L"FOO") == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(L"BAR") == S_OK);
Assert::IsTrue(renameRegEx->PutFileTime(SYSTEMTIME{0}) == S_OK);
Assert::IsTrue(renameRegEx->ResetFileTime() == S_OK);
Assert::IsTrue(lstrcmpi(L"FOO", mockEvents->m_searchTerm) == 0);
Assert::IsTrue(lstrcmpi(L"BAR", mockEvents->m_replaceTerm) == 0);
Assert::IsTrue(flags == mockEvents->m_flags);
Assert::IsTrue(renameRegEx->UnAdvise(cookie) == S_OK);
mockEvents->Release();
}
}; };
} }

View File

@@ -8,14 +8,6 @@ using namespace Microsoft::VisualStudio::CppUnitTestFramework;
namespace PowerRenameRegExTests namespace PowerRenameRegExTests
{ {
struct SearchReplaceExpected
{
PCWSTR search;
PCWSTR replace;
PCWSTR test;
PCWSTR expected;
};
TEST_CLASS(SimpleTests){ TEST_CLASS(SimpleTests){
public: public:
TEST_CLASS_INITIALIZE(ClassInitialize) TEST_CLASS_INITIALIZE(ClassInitialize)
@@ -23,241 +15,8 @@ TEST_CLASS_INITIALIZE(ClassInitialize)
CSettingsInstance().SetUseBoostLib(false); CSettingsInstance().SetUseBoostLib(false);
} }
TEST_METHOD(GeneralReplaceTest) #define TESTS_PARTIAL
{ #include "CommonRegExTests.h"
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(L"foo") == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(L"big") == S_OK);
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result) == S_OK);
Assert::IsTrue(wcscmp(result, L"bigbar") == 0);
CoTaskMemFree(result);
}
TEST_METHOD(ReplaceNoMatch)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(L"notfound") == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(L"big") == S_OK);
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result) == S_OK);
Assert::IsTrue(wcscmp(result, L"foobar") == 0);
CoTaskMemFree(result);
}
TEST_METHOD(ReplaceNoSearchOrReplaceTerm)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result) == S_OK);
Assert::IsTrue(result == nullptr);
CoTaskMemFree(result);
}
TEST_METHOD(ReplaceNoReplaceTerm)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(L"foo") == S_OK);
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result) == S_OK);
Assert::IsTrue(wcscmp(result, L"bar") == 0);
CoTaskMemFree(result);
}
TEST_METHOD(ReplaceEmptyStringReplaceTerm)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(L"foo") == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(L"") == S_OK);
Assert::IsTrue(renameRegEx->Replace(L"foobar", &result) == S_OK);
Assert::IsTrue(wcscmp(result, L"bar") == 0);
CoTaskMemFree(result);
}
TEST_METHOD(VerifyDefaultFlags)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = 0;
Assert::IsTrue(renameRegEx->GetFlags(&flags) == S_OK);
Assert::IsTrue(flags == 0);
}
TEST_METHOD(VerifyCaseSensitiveSearch)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = CaseSensitive;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
SearchReplaceExpected sreTable[] = {
{ L"Foo", L"Foo", L"FooBar", L"FooBar" },
{ L"Foo", L"boo", L"FooBar", L"booBar" },
{ L"Foo", L"boo", L"foobar", L"foobar" },
{ L"123", L"654", L"123456", L"654456" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyReplaceFirstOnly)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = 0;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
SearchReplaceExpected sreTable[] = {
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AABBA" },
{ L"B", L"BBB", L"ABABAB", L"ABBBABAB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyReplaceAll)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = MatchAllOccurrences;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
SearchReplaceExpected sreTable[] = {
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AAAAA" },
{ L"B", L"BBB", L"ABABAB", L"ABBBABBBABBB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyReplaceAllCaseInsensitive)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = MatchAllOccurrences | CaseSensitive;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
SearchReplaceExpected sreTable[] = {
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AAAAA" },
{ L"B", L"BBB", L"ABABAB", L"ABBBABBBABBB" },
{ L"b", L"BBB", L"AbABAb", L"ABBBABABBB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyReplaceFirstOnlyUseRegEx)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = UseRegularExpressions;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
SearchReplaceExpected sreTable[] = {
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AABBA" },
{ L"B", L"BBB", L"ABABAB", L"ABBBABAB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyReplaceAllUseRegEx)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = MatchAllOccurrences | UseRegularExpressions;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
SearchReplaceExpected sreTable[] = {
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AAAAA" },
{ L"B", L"BBB", L"ABABAB", L"ABBBABBBABBB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyReplaceAllUseRegExCaseSensitive)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
DWORD flags = MatchAllOccurrences | UseRegularExpressions | CaseSensitive;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
SearchReplaceExpected sreTable[] = {
{ L"B", L"BB", L"ABA", L"ABBA" },
{ L"B", L"A", L"ABBBA", L"AAAAA" },
{ L"b", L"BBB", L"AbABAb", L"ABBBABABBB" },
};
for (int i = 0; i < ARRAYSIZE(sreTable); i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyMatchAllWildcardUseRegEx) TEST_METHOD(VerifyMatchAllWildcardUseRegEx)
{ {
@@ -275,38 +34,13 @@ TEST_METHOD(VerifyMatchAllWildcardUseRegEx)
PWSTR result = nullptr; PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK); Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK); Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK); unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result, index) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0); Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result); CoTaskMemFree(result);
} }
} }
void VerifyReplaceFirstWildcard(SearchReplaceExpected sreTable[], int tableSize, DWORD flags)
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
for (int i = 0; i < tableSize; i++)
{
PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK);
Assert::AreEqual(sreTable[i].expected, result);
CoTaskMemFree(result);
}
}
TEST_METHOD(VerifyReplaceFirstWildCardUseRegex)
{
SearchReplaceExpected sreTable[] = {
//search, replace, test, result
{ L".*", L"Foo", L"AAAAAA", L"Foo" },
};
VerifyReplaceFirstWildcard(sreTable, ARRAYSIZE(sreTable), UseRegularExpressions);
}
TEST_METHOD(VerifyReplaceFirstWildCardUseRegexMatchAllOccurrences) TEST_METHOD(VerifyReplaceFirstWildCardUseRegexMatchAllOccurrences)
{ {
SearchReplaceExpected sreTable[] = { SearchReplaceExpected sreTable[] = {
@@ -316,27 +50,6 @@ TEST_METHOD(VerifyReplaceFirstWildCardUseRegexMatchAllOccurrences)
VerifyReplaceFirstWildcard(sreTable, ARRAYSIZE(sreTable), UseRegularExpressions | MatchAllOccurrences); VerifyReplaceFirstWildcard(sreTable, ARRAYSIZE(sreTable), UseRegularExpressions | MatchAllOccurrences);
} }
TEST_METHOD(VerifyReplaceFirstWildCardMatchAllOccurrences)
{
SearchReplaceExpected sreTable[] = {
//search, replace, test, result
{ L".*", L"Foo", L"AAAAAA", L"AAAAAA" },
{ L".*", L"Foo", L".*", L"Foo" },
{ L".*", L"Foo", L".*Bar.*", L"FooBarFoo" },
};
VerifyReplaceFirstWildcard(sreTable, ARRAYSIZE(sreTable), MatchAllOccurrences);
}
TEST_METHOD(VerifyReplaceFirstWildNoFlags)
{
SearchReplaceExpected sreTable[] = {
//search, replace, test, result
{ L".*", L"Foo", L"AAAAAA", L"AAAAAA" },
{ L".*", L"Foo", L".*", L"Foo" },
};
VerifyReplaceFirstWildcard(sreTable, ARRAYSIZE(sreTable), 0);
}
TEST_METHOD(VerifyHandleCapturingGroups) TEST_METHOD(VerifyHandleCapturingGroups)
{ {
CComPtr<IPowerRenameRegEx> renameRegEx; CComPtr<IPowerRenameRegEx> renameRegEx;
@@ -362,7 +75,8 @@ TEST_METHOD(VerifyHandleCapturingGroups)
PWSTR result = nullptr; PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK); Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK); Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK); unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result, index) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0); Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result); CoTaskMemFree(result);
} }
@@ -387,7 +101,8 @@ TEST_METHOD (VerifyFileAttributesNoPadding)
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK); Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK); Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->PutFileTime(fileTime) == S_OK); Assert::IsTrue(renameRegEx->PutFileTime(fileTime) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK); unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result, index) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0); Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result); CoTaskMemFree(result);
} }
@@ -411,7 +126,8 @@ TEST_METHOD (VerifyFileAttributesPadding)
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK); Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK); Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->PutFileTime(fileTime) == S_OK); Assert::IsTrue(renameRegEx->PutFileTime(fileTime) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK); unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result, index) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0); Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result); CoTaskMemFree(result);
} }
@@ -459,7 +175,8 @@ TEST_METHOD (VerifyFileAttributesMonthandDayNames)
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK); Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK); Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->PutFileTime(fileTime) == S_OK); Assert::IsTrue(renameRegEx->PutFileTime(fileTime) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == S_OK); unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result, index) == S_OK);
Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0); Assert::IsTrue(wcscmp(result, sreTable[i].expected) == 0);
CoTaskMemFree(result); CoTaskMemFree(result);
} }
@@ -483,33 +200,12 @@ TEST_METHOD(VerifyLookbehindFails)
PWSTR result = nullptr; PWSTR result = nullptr;
Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK); Assert::IsTrue(renameRegEx->PutSearchTerm(sreTable[i].search) == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK); Assert::IsTrue(renameRegEx->PutReplaceTerm(sreTable[i].replace) == S_OK);
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result) == E_FAIL); unsigned long index = {};
Assert::IsTrue(renameRegEx->Replace(sreTable[i].test, &result, index) == E_FAIL);
Assert::AreEqual(sreTable[i].expected, result); Assert::AreEqual(sreTable[i].expected, result);
CoTaskMemFree(result); CoTaskMemFree(result);
} }
} }
TEST_METHOD(VerifyEventsFire) };
{
CComPtr<IPowerRenameRegEx> renameRegEx;
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
CMockPowerRenameRegExEvents* mockEvents = new CMockPowerRenameRegExEvents();
CComPtr<IPowerRenameRegExEvents> regExEvents;
Assert::IsTrue(mockEvents->QueryInterface(IID_PPV_ARGS(&regExEvents)) == S_OK);
DWORD cookie = 0;
Assert::IsTrue(renameRegEx->Advise(regExEvents, &cookie) == S_OK);
DWORD flags = MatchAllOccurrences | UseRegularExpressions | CaseSensitive;
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
Assert::IsTrue(renameRegEx->PutSearchTerm(L"FOO") == S_OK);
Assert::IsTrue(renameRegEx->PutReplaceTerm(L"BAR") == S_OK);
Assert::IsTrue(renameRegEx->PutFileTime(SYSTEMTIME{ 0 }) == S_OK);
Assert::IsTrue(renameRegEx->ResetFileTime() == S_OK);
Assert::IsTrue(lstrcmpi(L"FOO", mockEvents->m_searchTerm) == 0);
Assert::IsTrue(lstrcmpi(L"BAR", mockEvents->m_replaceTerm) == 0);
Assert::IsTrue(flags == mockEvents->m_flags);
Assert::IsTrue(renameRegEx->UnAdvise(cookie) == S_OK);
mockEvents->Release();
}
}
;
} }

View File

@@ -3,11 +3,4 @@
#include "targetver.h" #include "targetver.h"
#include <atlbase.h> #include <atlbase.h>
#include "CppUnitTestInclude.h"
// Headers for CppUnitTest
// Suppressing 26466 - Don't use static_cast downcasts - in CppUnitTest.h
#pragma warning(push)
#pragma warning(disable : 26466)
#include "CppUnitTest.h"
#pragma warning(pop)