Skip to content
Open
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
53 changes: 53 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: CI

on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:

env:
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true

jobs:
build-and-test:
name: Build & Test (.NET 8, Windows)
runs-on: windows-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup .NET 8
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.x'

- name: Cache NuGet packages
uses: actions/cache@v4
with:
path: ~/.nuget/packages
key: ${{ runner.os }}-nuget-${{ hashFiles('src/**/*.csproj') }}
restore-keys: |
${{ runner.os }}-nuget-

- name: Restore
run: dotnet restore src/SplitWireTurkey.sln

- name: Build (Release)
run: dotnet build src/SplitWireTurkey.sln --configuration Release --no-restore

- name: Test
run: dotnet test src/SplitWireTurkey.Tests/SplitWireTurkey.Tests.csproj --configuration Release --no-build --logger "trx;LogFileName=test-results.trx" --results-directory ./TestResults

- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results
path: ./TestResults/**/*.trx
retention-days: 14
if-no-files-found: ignore
35 changes: 35 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Build outputs
[Bb]in/
[Oo]bj/
[Pp]ublish/
[Dd]ebug/
[Rr]elease/
*.user
*.suo
*.userprefs

# Test results
TestResults/
coverage*.xml
*.trx
*.coverage
*.coveragexml

# NuGet
.nuget/
*.nupkg
*.snupkg

# Visual Studio / Rider
.vs/
.vscode/
.idea/
*.sln.docstates

# OS
Thumbs.db
.DS_Store
desktop.ini

# Logs
*.log
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
[![RU](https://img.shields.io/badge/README-RU-blue.svg)](https://github.com/cagritaskn/SplitWire-Turkey/blob/main/.github/README_RU.md)
[![ES](https://img.shields.io/badge/README-ES-blue.svg)](https://github.com/cagritaskn/SplitWire-Turkey/blob/main/.github/README_ES.md)

[![CI](https://github.com/cagritaskn/SplitWire-Turkey/actions/workflows/ci.yml/badge.svg)](https://github.com/cagritaskn/SplitWire-Turkey/actions/workflows/ci.yml)

</div>

# SplitWire-Turkey
Expand Down Expand Up @@ -329,6 +331,18 @@ Gereksinimler:
..\build_simple.bat
```

4. **Testleri Çalıştırın (opsiyonel)**
```bash
# Çözüm dosyasından
dotnet test ..\SplitWireTurkey.sln -c Release

# Sadece test projesi
dotnet test ..\SplitWireTurkey.Tests\SplitWireTurkey.Tests.csproj
```
`VersionHelper` ve `LanguageManager` davranışı için xUnit testleri
`src/SplitWireTurkey.Tests/` altındadır. Aynı paketler GitHub Actions'taki
CI workflow'u tarafından her PR'da otomatik olarak çalıştırılır.

### InnoSetup Kullanarak Kurulum Yürütülebilirini Tekrar Derleme
Gereksinimler:
- **InnoSetup 6**
Expand Down
109 changes: 109 additions & 0 deletions src/SplitWireTurkey.Tests/LanguageManagerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
using SplitWireTurkey;
using Xunit;

namespace SplitWireTurkey.Tests
{
/// <summary>
/// LanguageManager is a static class — all tests live in a single
/// non-parallel collection so the shared state is deterministic.
/// </summary>
[Collection("LanguageManager")]
public class LanguageManagerTests
{
[Fact]
public void LoadLanguage_WithSupportedCode_ReturnsTrue()
{
Assert.True(LanguageManager.LoadLanguage("TR"));
Assert.Equal("TR", LanguageManager.CurrentLanguage);
}

[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
public void LoadLanguage_WithNullOrBlank_ReturnsFalseAndDoesNotThrow(string code)
{
// Must never throw NullReferenceException / ArgumentNullException.
var result = LanguageManager.LoadLanguage(code);
Assert.False(result);
}

[Fact]
public void LoadLanguage_WithUnknownCode_FallsBackAndStillExposesKeys()
{
// Unknown language file does not exist on disk, but the
// Turkish fallback dictionary should still resolve common keys.
var ok = LanguageManager.LoadLanguage("XX");
Assert.True(ok);

var translated = LanguageManager.GetText("buttons", "exit");
Assert.NotEqual("buttons.exit", translated);
Assert.False(string.IsNullOrWhiteSpace(translated));
}

[Fact]
public void GetText_TopLevelKey_ReturnsLocalizedString()
{
LanguageManager.LoadLanguage("EN");
// No top-level scalar keys exist by default, so this also
// verifies that an unknown flat key returns the key itself.
Assert.Equal("nonexistent_top_level_key",
LanguageManager.GetText("nonexistent_top_level_key"));
}

[Fact]
public void GetText_NestedKey_ReturnsLocalizedString_ForTurkish()
{
LanguageManager.LoadLanguage("TR");

Assert.Equal("WireSock", LanguageManager.GetText("tabs", "main"));
Assert.Equal("Çıkış", LanguageManager.GetText("buttons", "exit"));
}

[Fact]
public void GetText_NestedKey_ReturnsLocalizedString_ForEnglish()
{
LanguageManager.LoadLanguage("EN");

Assert.Equal("Exit", LanguageManager.GetText("buttons", "exit"));
Assert.Equal("Administrator Privileges Required",
LanguageManager.GetText("messages", "admin_required_title"));
}

[Fact]
public void GetText_UnknownNestedKey_ReturnsCategoryDotKey()
{
LanguageManager.LoadLanguage("TR");

Assert.Equal("buttons.does_not_exist",
LanguageManager.GetText("buttons", "does_not_exist"));
Assert.Equal("no_such_category.foo",
LanguageManager.GetText("no_such_category", "foo"));
}

[Fact]
public void GetText_NullKey_ReturnsNull()
{
LanguageManager.LoadLanguage("TR");

Assert.Null(LanguageManager.GetText(key: null));
Assert.Null(LanguageManager.GetText(category: null, key: "x"));
Assert.Null(LanguageManager.GetText(category: "x", key: null));
}

[Fact]
public void GetText_FormatsArguments()
{
// Use a key that exists in TR and contains a {0} placeholder.
// messages.unexpected_error_message contains "Beklenmeyen bir hata oluştu:\n{0}".
LanguageManager.LoadLanguage("TR");

var formatted = LanguageManager.GetText("messages", "unexpected_error_message", "boom");
Assert.Contains("boom", formatted);
Assert.DoesNotContain("{0}", formatted);
}
}

[CollectionDefinition("LanguageManager", DisableParallelization = true)]
public class LanguageManagerCollection { }
}
39 changes: 39 additions & 0 deletions src/SplitWireTurkey.Tests/SplitWireTurkey.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<RootNamespace>SplitWireTurkey.Tests</RootNamespace>
<AssemblyName>SplitWireTurkey.Tests</AssemblyName>
<Nullable>disable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="xunit" Version="2.9.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\SplitWireTurkey\SplitWireTurkey.csproj" />
</ItemGroup>

<!--
LanguageManager reads JSON from {AppDomain.BaseDirectory}\res\Languages\.
We mirror the production layout in the test bin folder so tests
exercise real translation files instead of the failure path.
-->
<ItemGroup>
<Content Include="..\SplitWireTurkey\Resources\Languages\*.json">
<Link>res\Languages\%(Filename)%(Extension)</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

</Project>
47 changes: 47 additions & 0 deletions src/SplitWireTurkey.Tests/VersionHelperTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System;
using System.Text.RegularExpressions;
using SplitWireTurkey;
using Xunit;

namespace SplitWireTurkey.Tests
{
public class VersionHelperTests
{
private static readonly Regex VersionRegex = new(@"^\d+\.\d+\.\d+(\.\d+)?", RegexOptions.Compiled);

[Fact]
public void GetAssemblyVersion_ReturnsParsableVersion()
{
var version = VersionHelper.GetAssemblyVersion();

Assert.False(string.IsNullOrWhiteSpace(version));
Assert.True(Version.TryParse(version, out _), $"Not a valid Version: {version}");
}

[Fact]
public void GetFileVersion_ReturnsParsableVersion()
{
var version = VersionHelper.GetFileVersion();

Assert.False(string.IsNullOrWhiteSpace(version));
Assert.True(Version.TryParse(version, out _), $"Not a valid Version: {version}");
}

[Fact]
public void GetProductVersion_StartsWithSemverLikePrefix()
{
var version = VersionHelper.GetProductVersion();

Assert.False(string.IsNullOrWhiteSpace(version));
Assert.Matches(VersionRegex, version);
}

[Fact]
public void AllAccessors_AreDeterministic()
{
Assert.Equal(VersionHelper.GetAssemblyVersion(), VersionHelper.GetAssemblyVersion());
Assert.Equal(VersionHelper.GetFileVersion(), VersionHelper.GetFileVersion());
Assert.Equal(VersionHelper.GetProductVersion(), VersionHelper.GetProductVersion());
}
}
}
6 changes: 6 additions & 0 deletions src/SplitWireTurkey.Tests/xunit.runner.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"$schema": "https://xunit.net/schema/current/xunit.runner.schema.json",
"parallelizeAssembly": false,
"parallelizeTestCollections": false,
"methodDisplay": "method"
}
48 changes: 48 additions & 0 deletions src/SplitWireTurkey.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SplitWireTurkey", "SplitWireTurkey\SplitWireTurkey.csproj", "{CDE4D0B2-5B4F-4257-A177-D2C0BBD47E9C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SplitWireTurkey.Tests", "SplitWireTurkey.Tests\SplitWireTurkey.Tests.csproj", "{E46300A8-529E-4A1F-A244-D88C80B3531A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CDE4D0B2-5B4F-4257-A177-D2C0BBD47E9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CDE4D0B2-5B4F-4257-A177-D2C0BBD47E9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CDE4D0B2-5B4F-4257-A177-D2C0BBD47E9C}.Debug|x64.ActiveCfg = Debug|Any CPU
{CDE4D0B2-5B4F-4257-A177-D2C0BBD47E9C}.Debug|x64.Build.0 = Debug|Any CPU
{CDE4D0B2-5B4F-4257-A177-D2C0BBD47E9C}.Debug|x86.ActiveCfg = Debug|Any CPU
{CDE4D0B2-5B4F-4257-A177-D2C0BBD47E9C}.Debug|x86.Build.0 = Debug|Any CPU
{CDE4D0B2-5B4F-4257-A177-D2C0BBD47E9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CDE4D0B2-5B4F-4257-A177-D2C0BBD47E9C}.Release|Any CPU.Build.0 = Release|Any CPU
{CDE4D0B2-5B4F-4257-A177-D2C0BBD47E9C}.Release|x64.ActiveCfg = Release|Any CPU
{CDE4D0B2-5B4F-4257-A177-D2C0BBD47E9C}.Release|x64.Build.0 = Release|Any CPU
{CDE4D0B2-5B4F-4257-A177-D2C0BBD47E9C}.Release|x86.ActiveCfg = Release|Any CPU
{CDE4D0B2-5B4F-4257-A177-D2C0BBD47E9C}.Release|x86.Build.0 = Release|Any CPU
{E46300A8-529E-4A1F-A244-D88C80B3531A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E46300A8-529E-4A1F-A244-D88C80B3531A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E46300A8-529E-4A1F-A244-D88C80B3531A}.Debug|x64.ActiveCfg = Debug|Any CPU
{E46300A8-529E-4A1F-A244-D88C80B3531A}.Debug|x64.Build.0 = Debug|Any CPU
{E46300A8-529E-4A1F-A244-D88C80B3531A}.Debug|x86.ActiveCfg = Debug|Any CPU
{E46300A8-529E-4A1F-A244-D88C80B3531A}.Debug|x86.Build.0 = Debug|Any CPU
{E46300A8-529E-4A1F-A244-D88C80B3531A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E46300A8-529E-4A1F-A244-D88C80B3531A}.Release|Any CPU.Build.0 = Release|Any CPU
{E46300A8-529E-4A1F-A244-D88C80B3531A}.Release|x64.ActiveCfg = Release|Any CPU
{E46300A8-529E-4A1F-A244-D88C80B3531A}.Release|x64.Build.0 = Release|Any CPU
{E46300A8-529E-4A1F-A244-D88C80B3531A}.Release|x86.ActiveCfg = Release|Any CPU
{E46300A8-529E-4A1F-A244-D88C80B3531A}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
Loading