Skip to content

Commit d40c1a6

Browse files
authored
Merge pull request #15 from magic5644/feat-refactor-code
2 parents 39ebb2a + 3160d50 commit d40c1a6

16 files changed

+449
-128
lines changed

CodeLineCounter.Tests/CodeAnalyzerTests.cs

+4-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public void TestAnalyzeSolution()
1212
var solutionPath = Path.GetFullPath(Path.Combine(basePath, "..", "..", "..", "..", "CodeLineCounter.sln"));
1313

1414
// Act
15-
var (metrics, projectTotals, totalLines, totalFiles, duplicationMap) = CodeAnalyzer.AnalyzeSolution(solutionPath);
15+
var (metrics, projectTotals, totalLines, totalFiles, duplicationMap) = CodeMetricsAnalyzer.AnalyzeSolution(solutionPath);
1616

1717
// Assert
1818
Assert.NotNull(metrics);
@@ -37,7 +37,7 @@ public void AnalyzeSourceCode_Should_Set_CurrentNamespace()
3737
};
3838

3939
// Act
40-
CodeAnalyzer.AnalyzeSourceCode(projectNamespaceMetrics, lines, out string? currentNamespace, out _, out _);
40+
CodeMetricsAnalyzer.AnalyzeSourceCode(projectNamespaceMetrics, lines, out string? currentNamespace, out _, out _);
4141

4242
// Assert
4343
Assert.Equal("MyNamespace", currentNamespace);
@@ -57,7 +57,7 @@ public void AnalyzeSourceCode_Should_Set_FileLineCount()
5757
};
5858

5959
// Act
60-
CodeAnalyzer.AnalyzeSourceCode(projectNamespaceMetrics, lines, out _, out int fileLineCount, out _);
60+
CodeMetricsAnalyzer.AnalyzeSourceCode(projectNamespaceMetrics, lines, out _, out int fileLineCount, out _);
6161

6262
// Assert - 3 lines only because comment lines are ignored
6363
Assert.Equal(3, fileLineCount);
@@ -77,7 +77,7 @@ public void AnalyzeSourceCode_Should_Set_FileCyclomaticComplexity()
7777
};
7878

7979
// Act
80-
CodeAnalyzer.AnalyzeSourceCode(projectNamespaceMetrics, lines, out _, out _, out int fileCyclomaticComplexity);
80+
CodeMetricsAnalyzer.AnalyzeSourceCode(projectNamespaceMetrics, lines, out _, out _, out int fileCyclomaticComplexity);
8181

8282
// Assert
8383
Assert.Equal(1, fileCyclomaticComplexity);

CodeLineCounter.Tests/CodeDuplicationCheckerTests.cs

-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
using System.Collections.Generic;
2-
using System.IO;
3-
using System.Linq;
41
using CodeLineCounter.Services;
5-
using Xunit;
62

73
namespace CodeLineCounter.Tests
84
{

CodeLineCounter.Tests/CoreUtilsTests.cs

+100
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,57 @@ public void ParseArguments_Should_Ignore_Invalid_Arguments()
5959
Assert.Equal("testDirectory", DirectoryPath);
6060
}
6161

62+
// ParseArguments correctly processes valid command line arguments with all options
63+
[Fact]
64+
public void ParseArguments_processes_valid_arguments_with_all_options()
65+
{
66+
// Arrange
67+
string[] args = new[] { "-verbose", "-d", "C:/test", "-format", "JSON", "-help" };
68+
69+
// Act
70+
var result = CoreUtils.ParseArguments(args);
71+
72+
// Assert
73+
Assert.True(result.Verbose);
74+
Assert.Equal("C:/test", result.DirectoryPath);
75+
Assert.True(result.Help);
76+
Assert.Equal(CoreUtils.ExportFormat.JSON, result.format);
77+
}
78+
79+
// ParseArguments handles empty or null argument array
80+
[Fact]
81+
public void ParseArguments_handles_empty_argument_array()
82+
{
83+
// Arrange
84+
string[] emptyArgs = Array.Empty<string>();
85+
86+
// Act
87+
var result = CoreUtils.ParseArguments(emptyArgs);
88+
89+
// Assert
90+
Assert.False(result.Verbose);
91+
Assert.Null(result.DirectoryPath);
92+
Assert.False(result.Help);
93+
Assert.Equal(CoreUtils.ExportFormat.CSV, result.format);
94+
}
95+
96+
// ParseArguments processes invalid format option gracefully
97+
[Fact]
98+
public void ParseArguments_handles_invalid_format_option()
99+
{
100+
// Arrange
101+
string[] args = new[] { "-format", "INVALID" };
102+
var consoleOutput = new StringWriter();
103+
Console.SetOut(consoleOutput);
104+
105+
// Act
106+
var result = CoreUtils.ParseArguments(args);
107+
108+
// Assert
109+
Assert.Equal(CoreUtils.ExportFormat.CSV, result.format);
110+
Assert.Contains("Invalid format", consoleOutput.ToString());
111+
}
112+
62113
[Fact]
63114
public void GetUserChoice_Should_Return_Valid_Choice()
64115
{
@@ -91,6 +142,39 @@ public void GetUserChoice_Should_Return_Invalid_Choice()
91142
Assert.Equal(-1, result);
92143
}
93144

145+
// GetUserChoice returns valid selection when input is within range
146+
[Fact]
147+
public void GetUserChoice_returns_valid_selection_for_valid_input()
148+
{
149+
// Arrange
150+
var input = "2";
151+
var consoleInput = new StringReader(input);
152+
Console.SetIn(consoleInput);
153+
154+
// Act
155+
int result = CoreUtils.GetUserChoice(3);
156+
157+
// Assert
158+
Assert.Equal(2, result);
159+
}
160+
161+
[Theory]
162+
[InlineData("")]
163+
[InlineData(" ")]
164+
[InlineData("abc")]
165+
public void GetUserChoice_handles_invalid_input(string input)
166+
{
167+
// Arrange
168+
var consoleInput = new StringReader(input);
169+
Console.SetIn(consoleInput);
170+
171+
// Act
172+
int result = CoreUtils.GetUserChoice(5);
173+
174+
// Assert
175+
Assert.Equal(-1, result);
176+
}
177+
94178
[Fact]
95179
public void DisplaySolutions_Should_Write_Solutions_To_Console()
96180
{
@@ -204,5 +288,21 @@ public void CheckSettings_WhenSettingsAreInvalid_ReturnsFalse()
204288
// Assert
205289
Assert.False(result);
206290
}
291+
292+
[Theory]
293+
[InlineData("CO.Solution.Build-CodeMetrics.txt", CoreUtils.ExportFormat.CSV)]
294+
[InlineData("CO.Solution.Build-CodeDuplications.json", CoreUtils.ExportFormat.JSON)]
295+
[InlineData("CO.Solution.Build-CodeMetrics.", CoreUtils.ExportFormat.CSV)]
296+
[InlineData("CO.Solution.Build-CodeDuplications.²", CoreUtils.ExportFormat.JSON)]
297+
[InlineData("metrics_789.csv", CoreUtils.ExportFormat.CSV)]
298+
public void get_export_file_name_with_extension_handles_alphanumeric(string fileName, CoreUtils.ExportFormat format)
299+
{
300+
// Act
301+
var result = CoreUtils.GetExportFileNameWithExtension(fileName, format);
302+
303+
// Assert
304+
Assert.Contains(Path.GetFileNameWithoutExtension(fileName), result);
305+
Assert.True(File.Exists(result) || !File.Exists(result));
306+
}
207307
}
208308
}

CodeLineCounter.Tests/CsvHandlerTests.cs

-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
using System.Collections.Generic;
2-
using System.Globalization;
3-
using System.IO;
4-
using CsvHelper;
5-
using System.Linq;
6-
using Xunit;
71
using CodeLineCounter.Utils;
82

93
namespace CodeLineCounter.Tests

CodeLineCounter.Tests/DataExporterTests.cs

-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
1-
using Xunit;
2-
using System;
3-
using System.IO;
4-
using System.Collections.Generic;
51
using CodeLineCounter.Models;
62
using CodeLineCounter.Utils;
7-
using System.Linq;
83

94
namespace CodeLineCounter.Tests
105
{
File renamed without changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
using CodeLineCounter.Services;
2+
using CodeLineCounter.Models;
3+
using CodeLineCounter.Utils;
4+
5+
namespace CodeLineCounter.Tests.Services
6+
{
7+
public class SolutionAnalyzerTest
8+
{
9+
10+
[Fact]
11+
public void PerformAnalysis_ShouldReturnCorrectAnalysisResult()
12+
{
13+
// Arrange
14+
var basePath = FileUtils.GetBasePath();
15+
var solutionPath = Path.GetFullPath(Path.Combine(basePath, "..", "..", "..", ".."));
16+
solutionPath = Path.Combine(solutionPath, "CodeLineCounter.sln");
17+
18+
// Act
19+
var result = SolutionAnalyzer.PerformAnalysis(solutionPath);
20+
21+
// Assert
22+
Assert.NotNull(result);
23+
Assert.Equal("CodeLineCounter.sln", result.SolutionFileName);
24+
}
25+
26+
[Fact]
27+
public void OutputAnalysisResults_ShouldPrintCorrectOutput()
28+
{
29+
// Arrange
30+
var result = new SolutionAnalyzer.AnalysisResult
31+
{
32+
Metrics = new List<NamespaceMetrics>(),
33+
ProjectTotals = new Dictionary<string, int>(),
34+
TotalLines = 1000,
35+
TotalFiles = 10,
36+
DuplicationMap = new List<DuplicationCode>(),
37+
ProcessingTime = TimeSpan.FromSeconds(10),
38+
SolutionFileName = "CodeLineCounter.sln",
39+
DuplicatedLines = 100
40+
};
41+
var verbose = true;
42+
43+
using (var sw = new StringWriter())
44+
{
45+
Console.SetOut(sw);
46+
47+
// Act
48+
SolutionAnalyzer.OutputAnalysisResults(result, verbose);
49+
50+
// Assert
51+
var output = sw.ToString();
52+
Assert.Contains("Processing completed, number of source files processed: 10", output);
53+
Assert.Contains("Total lines of code: 1000", output);
54+
Assert.Contains("Solution CodeLineCounter.sln has 100 duplicated lines of code.", output);
55+
Assert.Contains("Percentage of duplicated code: 10.00 %", output);
56+
Assert.Contains("Time taken: 0:10.000", output);
57+
}
58+
}
59+
60+
[Fact]
61+
public void OutputDetailedMetrics_ShouldPrintMetricsAndProjectTotals()
62+
{
63+
// Arrange
64+
var metrics = new List<NamespaceMetrics>
65+
{
66+
new NamespaceMetrics
67+
{
68+
ProjectName = "Project1",
69+
ProjectPath = "/path/to/project1",
70+
NamespaceName = "Namespace1",
71+
FileName = "File1.cs",
72+
FilePath = "/path/to/project1/File1.cs",
73+
LineCount = 100,
74+
CyclomaticComplexity = 10
75+
},
76+
new NamespaceMetrics
77+
{
78+
ProjectName = "Project2",
79+
ProjectPath = "/path/to/project2",
80+
NamespaceName = "Namespace2",
81+
FileName = "File2.cs",
82+
FilePath = "/path/to/project2/File2.cs",
83+
LineCount = 200,
84+
CyclomaticComplexity = 20
85+
}
86+
};
87+
88+
var projectTotals = new Dictionary<string, int>
89+
{
90+
{ "Project1", 100 },
91+
{ "Project2", 200 }
92+
};
93+
94+
using (var sw = new StringWriter())
95+
{
96+
Console.SetOut(sw);
97+
98+
// Act
99+
SolutionAnalyzer.OutputDetailedMetrics(metrics, projectTotals);
100+
101+
// Assert
102+
var expectedOutput =
103+
$"Project Project1 (/path/to/project1) - Namespace Namespace1 in file File1.cs (/path/to/project1/File1.cs) has 100 lines of code and a cyclomatic complexity of 10.{Environment.NewLine}" +
104+
$"Project Project2 (/path/to/project2) - Namespace Namespace2 in file File2.cs (/path/to/project2/File2.cs) has 200 lines of code and a cyclomatic complexity of 20.{Environment.NewLine}" +
105+
$"Project Project1 has 100 total lines of code.{Environment.NewLine}" +
106+
$"Project Project2 has 200 total lines of code.{Environment.NewLine}";
107+
108+
Assert.Equal(expectedOutput, sw.ToString());
109+
}
110+
}
111+
112+
}
113+
}

CodeLineCounter/Models/DuplicationCode.cs

+22
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,27 @@ public class DuplicationCode
1515
[Name("NbLines")]
1616
public int NbLines { get; set; }
1717
}
18+
19+
public class DuplicationInfo
20+
{
21+
[Name("Source File")]
22+
public required string SourceFile { get; set; }
23+
[Name("Start Line")]
24+
public int StartLine { get; set; }
25+
[Name("Nb Lines")]
26+
public int NbLines { get; set; }
27+
[Name("Duplicated Code")]
28+
public required string DuplicatedCode { get; set; }
29+
[Name("Duplicated In")]
30+
public required List<DuplicationLocation> Duplicates { get; set; }
31+
}
32+
33+
public class DuplicationLocation
34+
{
35+
[Name("File Path")]
36+
public required string FilePath { get; set; }
37+
[Name("Start Line")]
38+
public int StartLine { get; set; }
39+
}
1840
}
1941

0 commit comments

Comments
 (0)