Skip to content
Merged

sync #660

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
989c546
Bump MSTest to 3.10.1
dependabot[bot] Aug 11, 2025
4a8d85e
Merge pull request #3 from joecare99/master
ChristianRosewich Nov 14, 2025
0a797f6
Merge pull request #4 from joecare99/master
ChristianRosewich Nov 14, 2025
4b3791f
Merge pull request #5 from joecare99/master
ChristianRosewich Nov 17, 2025
697a7e8
Bump Microsoft.CodeAnalysis.CSharp from 4.14.0 to 5.0.0
dependabot[bot] Nov 24, 2025
2af5e1a
Bump Microsoft.Extensions.Configuration.UserSecrets from 9.0.10 to 10…
dependabot[bot] Nov 24, 2025
60523f7
Bump Microsoft.Extensions.DependencyInjection and Microsoft.Extension…
dependabot[bot] Nov 24, 2025
348dfa4
Bump Microsoft.Extensions.Logging.Abstractions from 9.0.10 to 10.0.0
dependabot[bot] Nov 24, 2025
68415ea
Merge remote-tracking branch 'remotes/GH_CSharp/Avalonia_Apps'
joecare99 Nov 24, 2025
76d086b
Merge pull request #654 from joecare99/dependabot/nuget/TestStatement…
joecare99 Nov 24, 2025
4e31b6b
Merge pull request #655 from joecare99/dependabot/nuget/TestStatement…
joecare99 Nov 24, 2025
6e7c8e2
Merge branch 'TestStatements' into dependabot/nuget/TestStatements/Te…
joecare99 Nov 24, 2025
42a031d
Merge pull request #657 from joecare99/dependabot/nuget/TestStatement…
joecare99 Nov 24, 2025
67c11d7
Merge pull request #658 from joecare99/dependabot/nuget/TestStatement…
joecare99 Nov 24, 2025
0a25dc5
Merge remote-tracking branch 'remotes/origin/dependabot/nuget/TestSta…
joecare99 Nov 24, 2025
cd7347d
Merge branch 'TestStatements' of https://github.com/joecare99/CSharp …
joecare99 Nov 24, 2025
472211c
Merge remote-tracking branch 'remotes/GH_CSharp/TestStatements'
joecare99 Nov 24, 2025
fd1120f
Merge remote-tracking branch 'remotes/origin/master' into TestStatements
joecare99 Nov 24, 2025
b3732c6
CSharpBible
joecare99 Nov 24, 2025
96b5d7c
Merge branch 'joecare99:master' into master
ChristianRosewich Nov 25, 2025
ec7129a
Aktualisierung von Paketen und Dokumentation
ChristianRosewich Nov 25, 2025
5e1c8d5
Merge branch 'master' of https://github.com/ChristianRosewich/CSharp
ChristianRosewich Nov 25, 2025
8170613
Merge branch 'TestStatements'
joecare99 Nov 25, 2025
a16fb73
Merge pull request #659 from ChristianRosewich/master
joecare99 Nov 25, 2025
34d79a5
Transpiler_pp
joecare99 Nov 25, 2025
5a04f32
Merge branch 'Transpiler_pp'
joecare99 Nov 25, 2025
a18bad6
Merge branch 'Transpiler_pp' of https://github.com/joecare99/CSharp i…
joecare99 Nov 25, 2025
b3b73cd
AboutEx
joecare99 Nov 25, 2025
19f20fc
DataAnalysis.Core
joecare99 Nov 25, 2025
5f4b832
DataAnalysis.WPF
joecare99 Nov 25, 2025
1f3c6b3
DataAnalysis.WPF.TestHarness
joecare99 Nov 25, 2025
80229ff
DataConvert.Console
joecare99 Nov 25, 2025
1c5e6aa
CSharpBible
joecare99 Nov 25, 2025
b079722
Merge remote-tracking branch 'GH_CSharp/CSharpBible'
joecare99 Nov 25, 2025
9b9d06f
Merge remote-tracking branch 'GH_CSharp/Avalonia_Apps'
joecare99 Nov 25, 2025
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
30 changes: 15 additions & 15 deletions CSharpBible/Data/Data.sln
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 18
VisualStudioVersion = 18.0.11111.16
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RepoMigrator.Core", "RepoMigrator\RepoMigrator.Core\RepoMigrator.Core\RepoMigrator.Core.csproj", "{5281BA89-6796-4C3E-8DDA-7A627896AC1A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "RepoMigrator", "RepoMigrator", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
ProjectSection(SolutionItems) = preProject
Directory.Build.props = Directory.Build.props
Expand Down Expand Up @@ -72,6 +70,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PictureDB.UI", "PictureDB\P
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommonDialogs_net", "..\Libraries\CommonDialogs\CommonDialogs_net.csproj", "{65F08D9B-F63E-14C2-C35D-C324E1E37785}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RepoMigrator.Core", "RepoMigrator\RepoMigrator.Core\RepoMigrator.Core.csproj", "{7C507273-B03C-6545-08E2-F89BFF1DEDAA}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -82,18 +82,6 @@ Global
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5281BA89-6796-4C3E-8DDA-7A627896AC1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5281BA89-6796-4C3E-8DDA-7A627896AC1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5281BA89-6796-4C3E-8DDA-7A627896AC1A}.Debug|x64.ActiveCfg = Debug|Any CPU
{5281BA89-6796-4C3E-8DDA-7A627896AC1A}.Debug|x64.Build.0 = Debug|Any CPU
{5281BA89-6796-4C3E-8DDA-7A627896AC1A}.Debug|x86.ActiveCfg = Debug|Any CPU
{5281BA89-6796-4C3E-8DDA-7A627896AC1A}.Debug|x86.Build.0 = Debug|Any CPU
{5281BA89-6796-4C3E-8DDA-7A627896AC1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5281BA89-6796-4C3E-8DDA-7A627896AC1A}.Release|Any CPU.Build.0 = Release|Any CPU
{5281BA89-6796-4C3E-8DDA-7A627896AC1A}.Release|x64.ActiveCfg = Release|Any CPU
{5281BA89-6796-4C3E-8DDA-7A627896AC1A}.Release|x64.Build.0 = Release|Any CPU
{5281BA89-6796-4C3E-8DDA-7A627896AC1A}.Release|x86.ActiveCfg = Release|Any CPU
{5281BA89-6796-4C3E-8DDA-7A627896AC1A}.Release|x86.Build.0 = Release|Any CPU
{387BDBC9-0123-4C86-98FA-FBF66522A4B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{387BDBC9-0123-4C86-98FA-FBF66522A4B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{387BDBC9-0123-4C86-98FA-FBF66522A4B9}.Debug|x64.ActiveCfg = Debug|Any CPU
Expand Down Expand Up @@ -382,12 +370,23 @@ Global
{65F08D9B-F63E-14C2-C35D-C324E1E37785}.Release|x64.Build.0 = Release|Any CPU
{65F08D9B-F63E-14C2-C35D-C324E1E37785}.Release|x86.ActiveCfg = Release|x86
{65F08D9B-F63E-14C2-C35D-C324E1E37785}.Release|x86.Build.0 = Release|x86
{7C507273-B03C-6545-08E2-F89BFF1DEDAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C507273-B03C-6545-08E2-F89BFF1DEDAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C507273-B03C-6545-08E2-F89BFF1DEDAA}.Debug|x64.ActiveCfg = Debug|Any CPU
{7C507273-B03C-6545-08E2-F89BFF1DEDAA}.Debug|x64.Build.0 = Debug|Any CPU
{7C507273-B03C-6545-08E2-F89BFF1DEDAA}.Debug|x86.ActiveCfg = Debug|Any CPU
{7C507273-B03C-6545-08E2-F89BFF1DEDAA}.Debug|x86.Build.0 = Debug|Any CPU
{7C507273-B03C-6545-08E2-F89BFF1DEDAA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C507273-B03C-6545-08E2-F89BFF1DEDAA}.Release|Any CPU.Build.0 = Release|Any CPU
{7C507273-B03C-6545-08E2-F89BFF1DEDAA}.Release|x64.ActiveCfg = Release|Any CPU
{7C507273-B03C-6545-08E2-F89BFF1DEDAA}.Release|x64.Build.0 = Release|Any CPU
{7C507273-B03C-6545-08E2-F89BFF1DEDAA}.Release|x86.ActiveCfg = Release|Any CPU
{7C507273-B03C-6545-08E2-F89BFF1DEDAA}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{5281BA89-6796-4C3E-8DDA-7A627896AC1A} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{387BDBC9-0123-4C86-98FA-FBF66522A4B9} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{0256D739-F882-4F8C-8820-570FB07687AA} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
{DB10ACCB-609B-4638-8629-89196580CB43} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
Expand All @@ -410,6 +409,7 @@ Global
{42156DBB-5FC0-3FE1-FC43-55400E7FDFAD} = {3C73C616-12F2-478C-9CAC-823780861BCD}
{BFCB4F4A-F6A3-EB13-DB02-B0C1979AFDEA} = {3C73C616-12F2-478C-9CAC-823780861BCD}
{65F08D9B-F63E-14C2-C35D-C324E1E37785} = {51F6C20B-003C-430C-BED7-2A89F834E4C0}
{7C507273-B03C-6545-08E2-F89BFF1DEDAA} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {128BE64A-28F5-47C5-A045-2352EF09BFBB}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net9.0;net8.0</TargetFrameworks>
<IsPackable>false</IsPackable>
<LangVersion>12.0</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<!-- MSTest v4 (angenommen Version 4.0.0 verfügbar) -->
<PackageReference Include="MSTest" Version="4.0.2" />

<PackageReference Include="NSubstitute" Version="5.3.0" />
<PackageReference Include="ClosedXML" Version="0.105.0" />

</ItemGroup>

<ItemGroup>

<ProjectReference Include="..\DataAnalysis.Core\DataAnalysis.Core.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
using System;
using System.Reflection;
using ClosedXML.Excel;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NSubstitute;
using DataAnalysis.Core.Export;

namespace DataAnalysis.Core.Tests;

// Pseudocode (Plan):
// 1. Per Reflection die private Methode ToXLCellValue ermitteln: BindingFlags.Instance | BindingFlags.NonPublic.
// 2. Instanz von TableExcelExporter erzeugen.
// 3. DataTestMethod mit mehreren DataRow Fällen:
// - null -> string.Empty
// - DBNull.Value -> string.Empty
// - bool true/false -> 1/0 (int)
// - int -> int
// - long im int-Bereich -> int
// - long außerhalb int-Bereich -> double
// - float/double Ganzzahl-Wert -> int
// - float/double mit Nachkommastellen -> double
// - double.NaN / double.PositiveInfinity -> kulturinvariant string ("NaN","Infinity")
// - string leer/Whitespace -> string.Empty
// - string Integer -> int
// - string Double -> double
// 4. Methode via MethodInfo.Invoke aufrufen, Ergebnis (XLCellValue) typ und Wert prüfen.
// 5. Separater Test: Interface ITableExporter via NSubstitute erzeugen und verifizieren,
// dass Reflection auf Interface die Methode nicht findet, aber auf konkretem Typ schon.
// 6. Assertions kurz und präzise.
// 7. Nutzung NSubstitute sicherstellen (Substitute.For<ITableExporter>()).

[TestClass]
public class TableExcelExporterTests
{
private static MethodInfo GetPrivateMethod(string name)
=> typeof(TableExcelExporter).GetMethod(name, BindingFlags.Instance | BindingFlags.NonPublic)
?? throw new InvalidOperationException($"Methode {name} nicht gefunden.");

[DataTestMethod]
[DataRow(TypeCode.Empty, null, "", TypeCode.String)] // null -> ""
[DataRow(TypeCode.DBNull, null, "", TypeCode.String)] // DBNull -> ""
[DataRow(TypeCode.Boolean, true, true, TypeCode.Boolean)] // true -> 1
[DataRow(TypeCode.Boolean, false, false, TypeCode.Boolean)] // false -> 0
[DataRow(TypeCode.Int32, 5, 5, TypeCode.Int32)] // int bleibt int
[DataRow(TypeCode.Int64, 5L, 5, TypeCode.Int32)] // long im int-Bereich -> int
[DataRow(TypeCode.Int64, 5000000000L, 5000000000d, TypeCode.Double)] // long außerhalb int-Bereich -> double
[DataRow(TypeCode.Single, 5.0f, 5, TypeCode.Int32)] // float Ganzzahl -> int
[DataRow(TypeCode.Single, 5.25f, 5.25d, TypeCode.Double)] // float mit Nachkommastellen -> double
[DataRow(TypeCode.Double, 5.0d, 5, TypeCode.Int32)] // double Ganzzahl -> int
[DataRow(TypeCode.Double, 5.125d, 5.125d, TypeCode.Double)] // double mit Nachkommastellen -> double
[DataRow(TypeCode.Double, double.NaN, "NaN", TypeCode.String)] // NaN -> string "NaN"
[DataRow(TypeCode.Double, double.PositiveInfinity, "Infinity", TypeCode.String)] // Infinity -> string
[DataRow(TypeCode.String, " ", "", TypeCode.String)] // Whitespace -> ""
[DataRow(TypeCode.String, "True", true, TypeCode.Boolean)] // String int -> int
[DataRow(TypeCode.String, "false", false, TypeCode.Boolean)] // String int -> int
[DataRow(TypeCode.String, "42", 42, TypeCode.Int32)] // String int -> int
[DataRow(TypeCode.String, "42.75", 42.75d, TypeCode.Double)] // String double (.) -> double
[DataRow(TypeCode.String, "1e-6", 1e-6d, TypeCode.Double)] // String double (.) -> double
[DataRow(TypeCode.String, "-4.2e3", -4.2e3d, TypeCode.Double)] // String double (.) -> double
[DataRow(TypeCode.String, "42,75", 42.75d, TypeCode.Double)] // String double (,) -> double
[DataRow(TypeCode.String, "42.7.5", "42.7.5", TypeCode.String)] // Ungültig -> string unverändert
[DataRow(TypeCode.String, "0010", "0010", TypeCode.String)] // Führende Nullen -> string
[DataRow(TypeCode.String, "0", 0, TypeCode.Int32)] // nur Null -> int
public void ToXLCellValue_Test(TypeCode inputTypeCode, object? inputRaw, object expectedValue, TypeCode expectedTypeCode)
{
// Eingabeobjekt aus TypeCode ableiten
object? input = inputTypeCode switch
{
TypeCode.Empty => null,
TypeCode.DBNull => DBNull.Value,
_ => inputRaw
};

// Erwarteten Typ aus TypeCode bestimmen
Type expectedType = expectedTypeCode switch
{
TypeCode.String => typeof(string),
TypeCode.Int32 => typeof(int),
TypeCode.Boolean => typeof(bool),
TypeCode.Double => typeof(double),
_ => throw new AssertFailedException("Nicht unterstützter erwarteter TypeCode.")
};

var exporter = new TableExcelExporter();
var mi = GetPrivateMethod("ToXLCellValue");

var xl = (XLCellValue)mi.Invoke(exporter, new[] { input })!;

object actualValue;
TypeCode actualTC;
if (xl.IsBlank)
{
actualValue = "";
actualTC = TypeCode.String;
}
else if (xl.IsText)
{
actualValue = xl.GetText();
actualTC = TypeCode.String;
}
else if (xl.IsNumber)
{
actualValue = xl.GetNumber();
actualTC = Math.Abs((double)actualValue % 1d) < 1e-10 ? TypeCode.Int32 : TypeCode.Double;
}
else if (xl.IsBoolean)
{
actualValue = xl.GetBoolean();
actualTC = TypeCode.Boolean;
}
else
{
actualValue = xl.ToString();
actualTC = TypeCode.String;
}

if (expectedType == typeof(string))
{
Assert.AreEqual(expectedValue.ToString(), actualValue?.ToString(), "Stringwert stimmt nicht.");
return;
}

if (expectedType == typeof(int))
{
Assert.AreEqual(expectedTypeCode, actualTC , "Erwartet int.");
Assert.AreEqual((int)expectedValue, (int)Math.Round((double)actualValue), "int-Wert stimmt nicht.");
}
else if (expectedType == typeof(double))
{
Assert.IsTrue(actualValue is double or int, "Erwartet double oder int Repräsentation.");
double actualDouble = actualValue is int ai ? ai : (double)actualValue;
Assert.AreEqual(Convert.ToDouble(expectedValue), actualDouble, 1e-12, "double-Wert stimmt nicht.");
}
else if (expectedType == typeof(bool))
{
Assert.IsInstanceOfType(actualValue, typeof(bool), "Erwartet bool.");
Assert.AreEqual((bool)expectedValue, (bool)actualValue, "bool-Wert stimmt nicht.");
}
else
{
Assert.Fail("Nicht unterstützter erwarteter Typ.");
}
}

[TestMethod]
public void Reflection_Finden_Der_Privaten_Methode_Ueber_Konkreten_Typ_Nicht_Ueber_Interface()
{
// Arrange
var ifaceSub = Substitute.For<DataAnalysis.Core.Export.Interfaces.ITableExporter>();
var viaInterface = ifaceSub.GetType().GetMethod("ToXLCellValue", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
var viaConcrete = typeof(TableExcelExporter).GetMethod("ToXLCellValue", BindingFlags.Instance | BindingFlags.NonPublic);

// Assert
Assert.IsNull(viaInterface, "Private Methode sollte über Interface-Proxy nicht gefunden werden.");
Assert.IsNotNull(viaConcrete, "Private Methode sollte über konkreten Typ gefunden werden.");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ namespace DataAnalysis.Core.Export.Interfaces;

public interface ITableExporter
{
Task<string> ExportAsync(DataTable table, string inputPath, string? outputPath, CancellationToken cancellationToken = default);
Task<string> ExportAsync(DataTable table, string inputPath, string? outputPath, CancellationToken cancellationToken = default, Action<double>? progressCallback = null);
}
Loading