Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions .github/workflows/ci_build.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: CI Build
name: Build and test

on:
push:
Expand All @@ -17,28 +17,45 @@ jobs:
build_platform: [Win32, x64, ARM64]

steps:
# Step 1: Check out the code from the repo
- name: Checkout repo
uses: actions/checkout@v4
with:
submodules: recursive

# Step 2: Prepare for build
- name: Pre Build
uses: microsoft/setup-msbuild@v2

# Step 3: Build projects and unit test
- name: Build
working-directory: src
run: msbuild NppJSONViewer.sln /m /p:configuration="${{ matrix.build_configuration }}" /p:platform="${{ matrix.build_platform }}" /p:PlatformToolset="v143"

# Step 4: Upload build binary artifacts
- name: Archive binaries artifacts
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.build_platform}}_${{ matrix.build_configuration}}
path: src\Build\Bin\${{ matrix.build_configuration}}\${{ matrix.build_platform}}\NPPJSONViewer.dll

# Step 5: Upload build pdb artifacts
- name: Archive symbols artifacts
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.build_platform}}_${{ matrix.build_configuration}}_pdb
path: src\Build\Bin\${{ matrix.build_configuration}}\${{ matrix.build_platform}}\NPPJSONViewer.pdb


# Step 6: Run unit tests for x86 | Release
- name: Run tests x86 | Release
if: matrix.build_platform == 'Win32' && matrix.build_configuration == 'Release'
run: |
cd src\Build\Bin\Release\Win32
./UnitTest.exe

# Step 7: Run unit tests for x64 | Release
- name: Run tests x64 | Release
if: matrix.build_platform == 'x64' && matrix.build_configuration == 'Release'
run: |
cd src\Build\Bin\Release\x64
./UnitTest.exe
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
[submodule "external/rapidjson"]
path = external/rapidjson
url = https://github.com/NPP-JSONViewer/rapidjson.git
[submodule "external/googletest"]
path = external/googletest
url = https://github.com/google/googletest.git
1 change: 1 addition & 0 deletions external/googletest
Submodule googletest added at 0953a1
14 changes: 14 additions & 0 deletions src/NPPJSONViewer.sln
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NPPJSONViewer", "NppJsonVie
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UtilityLib", "UtilityLib\UtilityLib.vcxproj", "{171CAFC6-E679-4B81-BF5B-049AC0FAB4F8}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTest", "..\tests\UnitTest\UnitTest.vcxproj", "{5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
Expand Down Expand Up @@ -41,6 +43,18 @@ Global
{171CAFC6-E679-4B81-BF5B-049AC0FAB4F8}.Release|Win32.Build.0 = Release|Win32
{171CAFC6-E679-4B81-BF5B-049AC0FAB4F8}.Release|x64.ActiveCfg = Release|x64
{171CAFC6-E679-4B81-BF5B-049AC0FAB4F8}.Release|x64.Build.0 = Release|x64
{5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Debug|ARM64.ActiveCfg = Debug|ARM64
{5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Debug|ARM64.Build.0 = Debug|ARM64
{5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Debug|Win32.ActiveCfg = Debug|Win32
{5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Debug|Win32.Build.0 = Debug|Win32
{5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Debug|x64.ActiveCfg = Debug|x64
{5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Debug|x64.Build.0 = Debug|x64
{5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Release|ARM64.ActiveCfg = Release|ARM64
{5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Release|ARM64.Build.0 = Release|ARM64
{5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Release|Win32.ActiveCfg = Release|Win32
{5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Release|Win32.Build.0 = Release|Win32
{5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Release|x64.ActiveCfg = Release|x64
{5A15FD53-E7C1-4F10-85FA-B7C3BB5D4D64}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
18 changes: 0 additions & 18 deletions src/NppJsonViewer/NPPJSONViewer.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -106,24 +106,6 @@
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">false</LinkIncremental>
<LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IncludePath>$(SolutionDir)UtilityLib;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IncludePath>$(SolutionDir)UtilityLib;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>$(SolutionDir)UtilityLib;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<IncludePath>$(SolutionDir)UtilityLib;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IncludePath>$(SolutionDir)UtilityLib;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<IncludePath>$(SolutionDir)UtilityLib;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<Optimization>Disabled</Optimization>
Expand Down
1 change: 1 addition & 0 deletions src/NppJsonViewerCommon.props
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<OutDir>$(SolutionDir)Build\Bin\$(Configuration)\$(Platform)\</OutDir>
<IntDir>$(SolutionDir)Build\Intermediate\$(ProjectName)\$(Configuration)\$(Platform)\</IntDir>
<ExternalIncludePath>$(SolutionDir)..\external\npp;$(SolutionDir)..\external\rapidjson\include;$(ExternalIncludePath)</ExternalIncludePath>
<IncludePath>$(SolutionDir)UtilityLib;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
Expand Down
2 changes: 1 addition & 1 deletion src/UtilityLib/Utility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ auto CUtility::GetFileExtension(const std::wstring &fileName) -> std::wstring

auto CUtility::GetTempFilePath() -> std::wstring
{
TCHAR tmpDir[1024];
TCHAR tmpDir[1024] {};
GetTempPath(1024, tmpDir);
return tmpDir;
}
Expand Down
166 changes: 166 additions & 0 deletions tests/UnitTest/StringHelperTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
#include <gtest/gtest.h>

#include <vector>
#include <string>

#include "StringHelper.h"

namespace Utility
{
class StringHelperTest : public ::testing::Test
{
protected:
void SetUp() override {}
void TearDown() override {}
};

// Test ReplaceAll with simple strings
TEST_F(StringHelperTest, ReplaceAll_ShouldReplaceSubstring)
{
std::string result = StringHelper::ReplaceAll("hello world", "world", "C++");
EXPECT_EQ(result, "hello C++");
}

TEST_F(StringHelperTest, ReplaceAll_ShouldReplaceMultipleOccurrences)
{
std::string result = StringHelper::ReplaceAll("a quick brown fox jumps over the lazy dog", "o", "0");
EXPECT_EQ(result, "a quick br0wn f0x jumps 0ver the lazy d0g");
}

TEST_F(StringHelperTest, ReplaceAll_NoOccurrences)
{
std::string result = StringHelper::ReplaceAll("hello world", "foo", "bar");
EXPECT_EQ(result, "hello world");
}

// Test ReplaceAll for wide strings
TEST_F(StringHelperTest, ReplaceAll_WideString_ShouldReplaceSubstring)
{
std::wstring result = StringHelper::ReplaceAll(L"hello world", L"world", L"C++");
EXPECT_EQ(result, L"hello C++");
}

TEST_F(StringHelperTest, ReplaceAll_WideString_NoOccurrences)
{
std::wstring result = StringHelper::ReplaceAll(L"hello world", L"foo", L"bar");
EXPECT_EQ(result, L"hello world");
}

// Test ToWstring with various encodings
TEST_F(StringHelperTest, ToWstring_ShouldConvertString)
{
std::wstring result = StringHelper::ToWstring("hello", CP_UTF8);
EXPECT_EQ(result, L"hello");
}

TEST_F(StringHelperTest, ToWstring_ShouldHandleEmptyString)
{
std::wstring result = StringHelper::ToWstring("", CP_UTF8);
EXPECT_EQ(result, L"");
}

TEST_F(StringHelperTest, ToWstring_InvalidEncoding_ShouldReturnEmpty)
{
std::wstring result = StringHelper::ToWstring("invalid", 9999); // Invalid codepage
EXPECT_EQ(result, L"");
}

// Test ToString with various encodings
TEST_F(StringHelperTest, ToString_ShouldConvertWstring)
{
std::string result = StringHelper::ToString(L"hello", CP_UTF8);
EXPECT_EQ(result, "hello");
}

TEST_F(StringHelperTest, ToString_ShouldHandleEmptyWstring)
{
std::string result = StringHelper::ToString(L"", CP_UTF8);
EXPECT_EQ(result, "");
}

TEST_F(StringHelperTest, ToString_InvalidEncoding_ShouldReturnEmpty)
{
std::string result = StringHelper::ToString(L"invalid", 9999); // Invalid codepage
EXPECT_EQ(result, "");
}

// Test Split for standard strings
TEST_F(StringHelperTest, Split_ShouldSplitStringByDelimiter)
{
std::vector<std::string> result = StringHelper::Split("a,b,c", ",");
std::vector<std::string> expected = {"a", "b", "c"};
EXPECT_EQ(result.size(), expected.size());
EXPECT_EQ(result, expected);
}

TEST_F(StringHelperTest, Split_ShouldHandleEmptyString)
{
std::vector<std::string> result = StringHelper::Split("", ",");
EXPECT_TRUE(result.empty());
}

TEST_F(StringHelperTest, Split_ShouldHandleNoDelimiters)
{
std::vector<std::string> result = StringHelper::Split("abc", ",");
std::vector<std::string> expected = {"abc"};
EXPECT_EQ(result.size(), expected.size());
EXPECT_EQ(result, expected);
}

// Test Split for wide strings
TEST_F(StringHelperTest, Split_WideString_ShouldSplitStringByDelimiter)
{
std::vector<std::wstring> result = StringHelper::Split(L"a,b,c", L",");
std::vector<std::wstring> expected = {L"a", L"b", L"c"};
EXPECT_EQ(result.size(), expected.size());
EXPECT_EQ(result, expected);
}

TEST_F(StringHelperTest, Split_WideString_ShouldHandleEmptyString)
{
std::vector<std::wstring> result = StringHelper::Split(L"", L",");
EXPECT_TRUE(result.empty());
}

TEST_F(StringHelperTest, Split_WideString_ShouldHandleNoDelimiters)
{
std::vector<std::wstring> result = StringHelper::Split(L"abc", L",");
std::vector<std::wstring> expected = {L"abc"};
EXPECT_EQ(result.size(), expected.size());
EXPECT_EQ(result, expected);
}

// Test Contains method with case sensitivity
TEST_F(StringHelperTest, Contains_ShouldFindSubstring)
{
bool result = StringHelper::Contains("hello world", "world", false);
EXPECT_TRUE(result);
}

TEST_F(StringHelperTest, Contains_ShouldReturnFalseForNonExistingSubstring)
{
bool result = StringHelper::Contains("hello world", "foo", false);
EXPECT_FALSE(result);
}

TEST_F(StringHelperTest, Contains_IgnoreCase_ShouldFindSubstring)
{
bool result = StringHelper::Contains("Hello World", "world", true);
EXPECT_TRUE(result);
}

// Test ToLower
TEST_F(StringHelperTest, ToLower_ShouldConvertStringToLowercase)
{
std::string input = "HeLLo WoRLD";
StringHelper::ToLower(input);
EXPECT_EQ(input, "hello world");
}

TEST_F(StringHelperTest, ToLower_WideString_ShouldConvertToLowercase)
{
std::wstring input = L"HeLLo WoRLD";
StringHelper::ToLower(input);
EXPECT_EQ(input, L"hello world");
}
} // namespace Utility
Loading