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
8 changes: 4 additions & 4 deletions CodeLineCounter.Tests/CodeAnalyzerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public void TestAnalyzeSolution()
var solutionPath = Path.GetFullPath(Path.Combine(basePath, "..", "..", "..", "..", "CodeLineCounter.sln"));

// Act
var (metrics, projectTotals, totalLines, totalFiles, duplicationMap) = CodeAnalyzer.AnalyzeSolution(solutionPath);
var (metrics, projectTotals, totalLines, totalFiles, duplicationMap) = CodeMetricsAnalyzer.AnalyzeSolution(solutionPath);

// Assert
Assert.NotNull(metrics);
Expand All @@ -37,7 +37,7 @@ public void AnalyzeSourceCode_Should_Set_CurrentNamespace()
};

// Act
CodeAnalyzer.AnalyzeSourceCode(projectNamespaceMetrics, lines, out string? currentNamespace, out _, out _);
CodeMetricsAnalyzer.AnalyzeSourceCode(projectNamespaceMetrics, lines, out string? currentNamespace, out _, out _);

// Assert
Assert.Equal("MyNamespace", currentNamespace);
Expand All @@ -57,7 +57,7 @@ public void AnalyzeSourceCode_Should_Set_FileLineCount()
};

// Act
CodeAnalyzer.AnalyzeSourceCode(projectNamespaceMetrics, lines, out _, out int fileLineCount, out _);
CodeMetricsAnalyzer.AnalyzeSourceCode(projectNamespaceMetrics, lines, out _, out int fileLineCount, out _);

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

// Act
CodeAnalyzer.AnalyzeSourceCode(projectNamespaceMetrics, lines, out _, out _, out int fileCyclomaticComplexity);
CodeMetricsAnalyzer.AnalyzeSourceCode(projectNamespaceMetrics, lines, out _, out _, out int fileCyclomaticComplexity);

// Assert
Assert.Equal(1, fileCyclomaticComplexity);
Expand Down
4 changes: 0 additions & 4 deletions CodeLineCounter.Tests/CodeDuplicationCheckerTests.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using CodeLineCounter.Services;
using Xunit;

namespace CodeLineCounter.Tests
{
Expand Down
100 changes: 100 additions & 0 deletions CodeLineCounter.Tests/CoreUtilsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,57 @@ public void ParseArguments_Should_Ignore_Invalid_Arguments()
Assert.Equal("testDirectory", DirectoryPath);
}

// ParseArguments correctly processes valid command line arguments with all options
[Fact]
public void ParseArguments_processes_valid_arguments_with_all_options()
{
// Arrange
string[] args = new[] { "-verbose", "-d", "C:/test", "-format", "JSON", "-help" };

// Act
var result = CoreUtils.ParseArguments(args);

// Assert
Assert.True(result.Verbose);
Assert.Equal("C:/test", result.DirectoryPath);
Assert.True(result.Help);
Assert.Equal(CoreUtils.ExportFormat.JSON, result.format);
}

// ParseArguments handles empty or null argument array
[Fact]
public void ParseArguments_handles_empty_argument_array()
{
// Arrange
string[] emptyArgs = Array.Empty<string>();

// Act
var result = CoreUtils.ParseArguments(emptyArgs);

// Assert
Assert.False(result.Verbose);
Assert.Null(result.DirectoryPath);
Assert.False(result.Help);
Assert.Equal(CoreUtils.ExportFormat.CSV, result.format);
}

// ParseArguments processes invalid format option gracefully
[Fact]
public void ParseArguments_handles_invalid_format_option()
{
// Arrange
string[] args = new[] { "-format", "INVALID" };
var consoleOutput = new StringWriter();
Console.SetOut(consoleOutput);

// Act
var result = CoreUtils.ParseArguments(args);

// Assert
Assert.Equal(CoreUtils.ExportFormat.CSV, result.format);
Assert.Contains("Invalid format", consoleOutput.ToString());
}

[Fact]
public void GetUserChoice_Should_Return_Valid_Choice()
{
Expand Down Expand Up @@ -91,6 +142,39 @@ public void GetUserChoice_Should_Return_Invalid_Choice()
Assert.Equal(-1, result);
}

// GetUserChoice returns valid selection when input is within range
[Fact]
public void GetUserChoice_returns_valid_selection_for_valid_input()
{
// Arrange
var input = "2";
var consoleInput = new StringReader(input);
Console.SetIn(consoleInput);

// Act
int result = CoreUtils.GetUserChoice(3);

// Assert
Assert.Equal(2, result);
}

[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData("abc")]
public void GetUserChoice_handles_invalid_input(string input)
{
// Arrange
var consoleInput = new StringReader(input);
Console.SetIn(consoleInput);

// Act
int result = CoreUtils.GetUserChoice(5);

// Assert
Assert.Equal(-1, result);
}

[Fact]
public void DisplaySolutions_Should_Write_Solutions_To_Console()
{
Expand Down Expand Up @@ -204,5 +288,21 @@ public void CheckSettings_WhenSettingsAreInvalid_ReturnsFalse()
// Assert
Assert.False(result);
}

[Theory]
[InlineData("CO.Solution.Build-CodeMetrics.txt", CoreUtils.ExportFormat.CSV)]
[InlineData("CO.Solution.Build-CodeDuplications.json", CoreUtils.ExportFormat.JSON)]
[InlineData("CO.Solution.Build-CodeMetrics.", CoreUtils.ExportFormat.CSV)]
[InlineData("CO.Solution.Build-CodeDuplications.²", CoreUtils.ExportFormat.JSON)]
[InlineData("metrics_789.csv", CoreUtils.ExportFormat.CSV)]
public void get_export_file_name_with_extension_handles_alphanumeric(string fileName, CoreUtils.ExportFormat format)
{
// Act
var result = CoreUtils.GetExportFileNameWithExtension(fileName, format);

// Assert
Assert.Contains(Path.GetFileNameWithoutExtension(fileName), result);
Assert.True(File.Exists(result) || !File.Exists(result));
}
}
}
6 changes: 0 additions & 6 deletions CodeLineCounter.Tests/CsvHandlerTests.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using CsvHelper;
using System.Linq;
using Xunit;
using CodeLineCounter.Utils;

namespace CodeLineCounter.Tests
Expand Down
5 changes: 0 additions & 5 deletions CodeLineCounter.Tests/DataExporterTests.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
using Xunit;
using System;
using System.IO;
using System.Collections.Generic;
using CodeLineCounter.Models;
using CodeLineCounter.Utils;
using System.Linq;

namespace CodeLineCounter.Tests
{
Expand Down
113 changes: 113 additions & 0 deletions CodeLineCounter.Tests/SolutionAnalyzerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
using CodeLineCounter.Services;
using CodeLineCounter.Models;
using CodeLineCounter.Utils;

namespace CodeLineCounter.Tests.Services
{
public class SolutionAnalyzerTest
{

[Fact]
public void PerformAnalysis_ShouldReturnCorrectAnalysisResult()
{
// Arrange
var basePath = FileUtils.GetBasePath();
var solutionPath = Path.GetFullPath(Path.Combine(basePath, "..", "..", "..", ".."));
solutionPath = Path.Combine(solutionPath, "CodeLineCounter.sln");

// Act
var result = SolutionAnalyzer.PerformAnalysis(solutionPath);

// Assert
Assert.NotNull(result);
Assert.Equal("CodeLineCounter.sln", result.SolutionFileName);
}

[Fact]
public void OutputAnalysisResults_ShouldPrintCorrectOutput()
{
// Arrange
var result = new SolutionAnalyzer.AnalysisResult
{
Metrics = new List<NamespaceMetrics>(),
ProjectTotals = new Dictionary<string, int>(),
TotalLines = 1000,
TotalFiles = 10,
DuplicationMap = new List<DuplicationCode>(),
ProcessingTime = TimeSpan.FromSeconds(10),
SolutionFileName = "CodeLineCounter.sln",
DuplicatedLines = 100
};
var verbose = true;

using (var sw = new StringWriter())
{
Console.SetOut(sw);

// Act
SolutionAnalyzer.OutputAnalysisResults(result, verbose);

// Assert
var output = sw.ToString();
Assert.Contains("Processing completed, number of source files processed: 10", output);
Assert.Contains("Total lines of code: 1000", output);
Assert.Contains("Solution CodeLineCounter.sln has 100 duplicated lines of code.", output);
Assert.Contains("Percentage of duplicated code: 10.00 %", output);
Assert.Contains("Time taken: 0:10.000", output);
}
}

[Fact]
public void OutputDetailedMetrics_ShouldPrintMetricsAndProjectTotals()
{
// Arrange
var metrics = new List<NamespaceMetrics>
{
new NamespaceMetrics
{
ProjectName = "Project1",
ProjectPath = "/path/to/project1",
NamespaceName = "Namespace1",
FileName = "File1.cs",
FilePath = "/path/to/project1/File1.cs",
LineCount = 100,
CyclomaticComplexity = 10
},
new NamespaceMetrics
{
ProjectName = "Project2",
ProjectPath = "/path/to/project2",
NamespaceName = "Namespace2",
FileName = "File2.cs",
FilePath = "/path/to/project2/File2.cs",
LineCount = 200,
CyclomaticComplexity = 20
}
};

var projectTotals = new Dictionary<string, int>
{
{ "Project1", 100 },
{ "Project2", 200 }
};

using (var sw = new StringWriter())
{
Console.SetOut(sw);

// Act
SolutionAnalyzer.OutputDetailedMetrics(metrics, projectTotals);

// Assert
var expectedOutput =
$"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}" +
$"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}" +
$"Project Project1 has 100 total lines of code.{Environment.NewLine}" +
$"Project Project2 has 200 total lines of code.{Environment.NewLine}";

Assert.Equal(expectedOutput, sw.ToString());
}
}

}
}
22 changes: 22 additions & 0 deletions CodeLineCounter/Models/DuplicationCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,27 @@ public class DuplicationCode
[Name("NbLines")]
public int NbLines { get; set; }
}

public class DuplicationInfo
{
[Name("Source File")]
public required string SourceFile { get; set; }
[Name("Start Line")]
public int StartLine { get; set; }
[Name("Nb Lines")]
public int NbLines { get; set; }
[Name("Duplicated Code")]
public required string DuplicatedCode { get; set; }
[Name("Duplicated In")]
public required List<DuplicationLocation> Duplicates { get; set; }
}

public class DuplicationLocation
{
[Name("File Path")]
public required string FilePath { get; set; }
[Name("Start Line")]
public int StartLine { get; set; }
}
}

Loading
Loading