OSDN Git Service

Fix issue #1861: Some Substitution filter doesn't work
authorTakashi Sawanaka <sdottaka@users.sourceforge.net>
Tue, 23 May 2023 12:12:23 +0000 (21:12 +0900)
committerTakashi Sawanaka <sdottaka@users.sourceforge.net>
Tue, 23 May 2023 12:12:23 +0000 (21:12 +0900)
Src/SubstitutionFiltersList.cpp
Src/SubstitutionList.cpp
Testing/GoogleTest/SubstitutionList/SubstitutionList_test.cpp [new file with mode: 0644]
Testing/GoogleTest/UnitTests/UnitTests.vcxproj
Testing/GoogleTest/UnitTests/UnitTests.vcxproj.filters

index 680a514..0ae6caf 100644 (file)
@@ -21,7 +21,8 @@ static const tchar_t SubstitutionFiltersRegPath[] = _T("SubstitutionFilters");
  * @brief Default constructor.
  */
 SubstitutionFiltersList::SubstitutionFiltersList()
-: m_pOptionsMgr(nullptr)
+: m_enabled(false)
+, m_pOptionsMgr(nullptr)
 {
 }
 
index 4f79b5b..a8958da 100644 (file)
 #include <Poco/RegularExpression.h>
 #include "unicoder.h"
 
+static std::string replaceEscapeSequences(const std::string& input)
+{
+       std::string result;
+
+       for (size_t i = 0; i < input.size(); ++i)
+       {
+               if (input[i] == '\\')
+               {
+                       if (i + 1 < input.size())
+                       {
+                               switch (input[i + 1])
+                               {
+                               case 'a':
+                                       result += '\a';
+                                       break;
+                               case 'b':
+                                       result += '\b';
+                                       break;
+                               case 'f':
+                                       result += '\f';
+                                       break;
+                               case 'n':
+                                       result += '\n';
+                                       break;
+                               case 'r':
+                                       result += '\r';
+                                       break;
+                               case 't':
+                                       result += '\t';
+                                       break;
+                               case 'v':
+                                       result += '\v';
+                                       break;
+                               case 'x':
+                                       if (i + 3 < input.size())
+                                       {
+                                               std::string hexValue = input.substr(i + 2, 2);
+                                               try {
+                                                       unsigned int intValue = std::stoul(hexValue, nullptr, 16);
+                                                       result += static_cast<char>(intValue);
+                                                       i += 2;
+                                               }
+                                               catch (const std::invalid_argument&) {
+                                                       result += "\\x";
+                                               }
+                                       }
+                                       else
+                                       {
+                                               result += "\\x";
+                                       }
+                                       break;
+                               default:
+                                       if (isdigit(input[i + 1]))
+                                               result += '$';
+                                       result += input[i + 1];
+                                       break;
+                               }
+                               ++i;
+                       }
+               }
+               else
+               {
+                       result += input[i];
+               }
+       }
+
+       return result;
+}
+
 SubstitutionItem::SubstitutionItem(const std::string& pattern,
        const std::string& replacement, int regexpCompileOptions)
        : pattern(pattern)
-       , replacement(replacement)
+       , replacement(replaceEscapeSequences(replacement))
        , regexpCompileOptions(regexpCompileOptions)
        , regexp(pattern, regexpCompileOptions)
 {
diff --git a/Testing/GoogleTest/SubstitutionList/SubstitutionList_test.cpp b/Testing/GoogleTest/SubstitutionList/SubstitutionList_test.cpp
new file mode 100644 (file)
index 0000000..2ffb769
--- /dev/null
@@ -0,0 +1,64 @@
+#include "pch.h"
+#include <gtest/gtest.h>
+#include <vector>
+#include "SubstitutionList.h"
+#include "Environment.h"
+#include "paths.h"
+
+namespace
+{
+       // The fixture for testing string differencing functions.
+       class SubstitutionListTest : public testing::Test
+       {
+       protected:
+               // You can remove any or all of the following functions if its body
+               // is   empty.
+
+               SubstitutionListTest()
+               {
+                       // You can do set-up work for each test here.
+               }
+
+               virtual ~SubstitutionListTest()
+               {
+                       // You can do clean-up work     that doesn't throw exceptions here.
+               }
+
+               // If   the     constructor     and     destructor are not enough for setting up
+               // and cleaning up each test, you can define the following methods:
+
+               virtual void SetUp()
+               {
+                       // Code here will be called     immediately     after the constructor (right
+                       // before each test).
+               }
+
+               virtual void TearDown()
+               {
+                       // Code here will be called     immediately     after each test (right
+                       // before the destructor).
+               }
+
+               // Objects declared here can be used by all tests in the test case for Foo.
+               SubstitutionList m_substitutionList;
+       };
+
+       TEST_F(SubstitutionListTest, test)
+       {
+               SubstitutionList list;
+               EXPECT_FALSE(list.HasRegExps());
+               list.Add("abc", "\\a\\b\\f\\n\\r\\t\\v", Poco::RegularExpression::RE_MULTILINE);
+               EXPECT_TRUE(list.HasRegExps());
+               list.Add("([0-9]+) ([A-Z]+)", "\\2-\\1", Poco::RegularExpression::RE_MULTILINE);
+               list.Add("def", "\\x01\\xEF\\xab\\x", Poco::RegularExpression::RE_MULTILINE);
+               EXPECT_EQ(3, list.GetCount());
+               EXPECT_EQ("-\a\b\f\n\r\t\v-", list.Subst("-abc-"));
+               EXPECT_EQ("-ABCD-0123-", list.Subst("-0123 ABCD-"));
+               EXPECT_EQ("\x01\xef\xab\\x", list.Subst("def"));
+               list.RemoveAllFilters();
+               EXPECT_EQ(0, list.GetCount());
+       }
+
+
+
+}  // namespace
index 68532f5..546b902 100644 (file)
     </ClCompile>
     <ClCompile Include="..\..\..\Src\HashCalc.cpp" />
     <ClCompile Include="..\..\..\Src\PropertySystem.cpp" />
+    <ClCompile Include="..\..\..\Src\SubstitutionList.cpp" />
     <ClCompile Include="..\BinaryCompare\BinaryCompare_test.cpp">
       <PrecompiledHeader>Use</PrecompiledHeader>
       <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
       <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
       <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName)2.pch</PrecompiledHeaderOutputFile>
     </ClCompile>
+    <ClCompile Include="..\DirFilter\DirFilters_test.cpp">
+      <PrecompiledHeader>Use</PrecompiledHeader>
+      <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+      <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName)2.pch</PrecompiledHeaderOutputFile>
+    </ClCompile>
     <ClCompile Include="..\DirWatcher\DirWatcher_test.cpp" />
     <ClCompile Include="..\PropertySystem\PropertySystem_test.cpp" />
     <ClCompile Include="..\ShellFileOperations\ShellFileOperations_test.cpp">
       <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
       <PrecompiledHeaderOutputFile>$(IntDir)$(TargetName)2.pch</PrecompiledHeaderOutputFile>
     </ClCompile>
+    <ClCompile Include="..\SubstitutionList\SubstitutionList_test.cpp" />
     <ClCompile Include="..\TimeSizeCompare\TimeSizeCompare_test.cpp">
       <PrecompiledHeader>Use</PrecompiledHeader>
       <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
     <ClInclude Include="..\..\..\Src\Common\unicoder.h" />
     <ClInclude Include="..\..\..\Src\Common\UnicodeString.h" />
     <ClInclude Include="..\..\..\Src\Common\varprop.h" />
+    <ClInclude Include="..\..\..\Src\SubstitutionList.h" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
index fea2f16..fe4cace 100644 (file)
     <ClCompile Include="..\..\..\Src\Common\cio.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\DirFilter\DirFilters_test.cpp">
+      <Filter>Tests</Filter>
+    </ClCompile>
+    <ClCompile Include="..\SubstitutionList\SubstitutionList_test.cpp">
+      <Filter>Tests</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\Src\SubstitutionList.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\..\Src\CompareEngines\ByteComparator.h">
     <ClInclude Include="..\..\..\Src\Common\cio.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\..\Src\SubstitutionList.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>
\ No newline at end of file