Skip to content

Commit

Permalink
Refactoring (#14)
Browse files Browse the repository at this point in the history
* Refactored duplicated code

* Refactored, tidied up

* Added summariser tests

* Added durations to summariser

* Summarised duration inside scenario and steps, colour corrections for tag charts and tag value summaries; included tagged test cases for XorNUnit

* Corrected tag extraction for test cases for MSTest

* Added build configuration to report, inferred from extractors
  • Loading branch information
gubpalma authored Apr 12, 2024
1 parent 7928c77 commit f4e9c7a
Show file tree
Hide file tree
Showing 29 changed files with 1,349 additions and 1,124 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ namespace SpecFlowToMarkdown.Domain.TestAssembly
public class SpecFlowAssembly
{
public string AssemblyName { get; set; }

public string BuildConfiguration { get; set; }

public IEnumerable<SpecFlowFeature> Features { get; set; }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using SpecFlowToMarkdown.Domain;
using SpecFlowToMarkdown.Domain.TestAssembly;
using SpecFlowToMarkdown.Infrastructure.AssemblyLoad.Extractors;
using SpecFlowToMarkdown.Infrastructure.AssemblyLoad.Extractors.Feature;
using SpecFlowToMarkdown.Infrastructure.Io;

namespace SpecFlowToMarkdown.Infrastructure.AssemblyLoad
Expand Down Expand Up @@ -35,7 +36,7 @@ public SpecFlowAssembly Perform(ProgramArguments arguments)

var result =
_featureExtractor
.ExtractFeatures(assembly);
.Perform(assembly);

return result;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;

namespace SpecFlowToMarkdown.Infrastructure.AssemblyLoad.Configuration
{
public class BuildConfiguration : IBuildConfiguration
{
public IEnumerable<Tuple<string, int, int, int>> Get()
{
var buildConfigurations = new List<Tuple<string, int, int, int>>
{
new(
"Debug",
3,
5,
30
), // debug
new(
"Release",
2,
4,
19
) // release
};

return buildConfigurations;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;

namespace SpecFlowToMarkdown.Infrastructure.AssemblyLoad.Configuration
{
public interface IBuildConfiguration
{
public IEnumerable<Tuple<string, int, int, int>> Get();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using Mono.Cecil.Cil;

namespace SpecFlowToMarkdown.Infrastructure.AssemblyLoad.Extractors.Extensions
namespace SpecFlowToMarkdown.Infrastructure.AssemblyLoad.Extensions
{
internal static class InstructionEx
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Logging;
using Mono.Cecil;
using Mono.Cecil.Cil;
using SpecFlowToMarkdown.Domain.TestAssembly;
using SpecFlowToMarkdown.Infrastructure.AssemblyLoad.Extensions;
using SpecFlowToMarkdown.Infrastructure.AssemblyLoad.Extractors.Scenario;
using SpecFlowToMarkdown.Infrastructure.AssemblyLoad.Utils;

namespace SpecFlowToMarkdown.Infrastructure.AssemblyLoad.Extractors.Feature
{
public class FeatureExtractor : IFeatureExtractor
{
private readonly IEnumerable<IScenarioExtractor> _extractors;
private readonly ILogger<FeatureExtractor> _logger;

public FeatureExtractor(
ILogger<FeatureExtractor> logger,
IEnumerable<IScenarioExtractor> extractors
)
{
_logger = logger;
_extractors = extractors;
}

public SpecFlowAssembly Perform(AssemblyDefinition assembly)
{
var assemblyName =
assembly
.Name
.Name;

var inferredBuildConfiguration = "Unknown";

_logger
.LogInformation($"Assembly name: [{assemblyName}]");

var result = new SpecFlowAssembly
{
AssemblyName = assemblyName
};

var resultFeatures = new List<SpecFlowFeature>();

foreach (var module in assembly.Modules)
{
foreach (var type in module.Types)
{
if (type.CustomAttributes
.Any(
o =>
o
.ConstructorArguments
.Any(
arg =>
arg.Value != null && arg.Value.ToString() == Constants.CustomFeatureAttributeValue
)
))
{
_logger
.LogInformation($"Found {type.Methods.Count} feature methods in assembly [{assemblyName}]");

foreach (var method in type.Methods)
{
if (method.Name != Constants.FeatureSetupMethodName) continue;

foreach (var instruction in
method
.Body
.Instructions
.Where(o => o.OpCode == OpCodes.Newobj))
{
if (instruction.Operand is not MethodReference methodReference) continue;

if (methodReference.DeclaringType.FullName != Constants.FeatureInfoTypeName) continue;

var description = string.Empty;
var title = string.Empty;
var folderPath = string.Empty;

var currInstr =
instruction
.StepPrevious(3);

if (currInstr.OpCode == OpCodes.Ldstr)
{
description =
currInstr
.Operand
.ToString();

currInstr =
currInstr
.Previous;
}

if (currInstr.OpCode == OpCodes.Ldstr)
{
title =
currInstr
.Operand
.ToString();

_logger
.LogInformation($"Extracted feature: [{title}]");

currInstr =
currInstr
.Previous;
}

if (currInstr.OpCode == OpCodes.Ldstr)
{
folderPath =
currInstr
.Operand
.ToString();
}

var feature = new SpecFlowFeature
{
FolderPath = folderPath,
Title = title,
Description = description
};

var scenarios = new List<SpecFlowScenario>();

foreach (var typeMethod in type.Methods)
{
var applicableExtractor =
_extractors
.FirstOrDefault(o => o.IsApplicable(typeMethod));

if (applicableExtractor == null)
{
_logger
.LogWarning($"Could not find applicable scenario extractor for method type [{typeMethod.Name}]");

continue;
}

var scenario =
applicableExtractor
.Perform(
typeMethod,
type,
ref inferredBuildConfiguration
);

scenarios
.Add(scenario);
}

feature.Scenarios = scenarios;

resultFeatures
.Add(feature);
}
}
}
}
}

result.Features = resultFeatures;

result.BuildConfiguration = inferredBuildConfiguration;

return result;
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
using Mono.Cecil;
using SpecFlowToMarkdown.Domain.TestAssembly;

namespace SpecFlowToMarkdown.Infrastructure.AssemblyLoad.Extractors
namespace SpecFlowToMarkdown.Infrastructure.AssemblyLoad.Extractors.Feature
{
public interface IFeatureExtractor
{
public SpecFlowAssembly ExtractFeatures(AssemblyDefinition assembly);
public SpecFlowAssembly Perform(AssemblyDefinition assembly);
}
}
Loading

0 comments on commit f4e9c7a

Please sign in to comment.