1791 lines
61 KiB
C#
Executable File
1791 lines
61 KiB
C#
Executable File
using Microsoft.CodeAnalysis;
|
|
using Microsoft.CodeAnalysis.CSharp;
|
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text.Json;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace MarketAlly.AIPlugin.Analysis.Plugins
|
|
{
|
|
[AIPlugin("BehaviorAnalysis", "Analyzes code behavior against specifications and detects semantic drift")]
|
|
public class BehaviorAnalysisPlugin : IAIPlugin
|
|
{
|
|
[AIParameter("Full path to the file or directory to analyze", required: true)]
|
|
public string Path { get; set; } = string.Empty;
|
|
|
|
[AIParameter("Path to specification file or documentation", required: false)]
|
|
public string SpecificationPath { get; set; } = string.Empty;
|
|
|
|
[AIParameter("Generate natural language summaries of code behavior", required: false)]
|
|
public bool GenerateSummaries { get; set; } = true;
|
|
|
|
[AIParameter("Compare behavior against previous versions", required: false)]
|
|
public bool CompareVersions { get; set; } = false;
|
|
|
|
[AIParameter("Detect breaking changes in public APIs", required: false)]
|
|
public bool DetectBreakingChanges { get; set; } = true;
|
|
|
|
[AIParameter("Validate intent alignment with specifications", required: false)]
|
|
public bool ValidateIntent { get; set; } = true;
|
|
|
|
[AIParameter("Generate behavior test suggestions", required: false)]
|
|
public bool SuggestTests { get; set; } = true;
|
|
|
|
public IReadOnlyDictionary<string, Type> SupportedParameters => new Dictionary<string, Type>
|
|
{
|
|
["path"] = typeof(string),
|
|
["specificationPath"] = typeof(string),
|
|
["generateSummaries"] = typeof(bool),
|
|
["compareVersions"] = typeof(bool),
|
|
["detectBreakingChanges"] = typeof(bool),
|
|
["validateIntent"] = typeof(bool),
|
|
["suggestTests"] = typeof(bool)
|
|
};
|
|
|
|
public async Task<AIPluginResult> ExecuteAsync(IReadOnlyDictionary<string, object> parameters)
|
|
{
|
|
try
|
|
{
|
|
// Extract parameters
|
|
string path = parameters["path"]?.ToString() ?? string.Empty;
|
|
string? specificationPath = parameters.TryGetValue("specificationPath", out var specPath)
|
|
? specPath?.ToString()
|
|
: null;
|
|
bool generateSummaries = GetBoolParameter(parameters, "generateSummaries", true);
|
|
bool compareVersions = GetBoolParameter(parameters, "compareVersions", false);
|
|
bool detectBreakingChanges = GetBoolParameter(parameters, "detectBreakingChanges", true);
|
|
bool validateIntent = GetBoolParameter(parameters, "validateIntent", true);
|
|
bool suggestTests = GetBoolParameter(parameters, "suggestTests", true);
|
|
|
|
// Validate path
|
|
if (!File.Exists(path) && !Directory.Exists(path))
|
|
{
|
|
return new AIPluginResult(
|
|
new FileNotFoundException($"Path not found: {path}"),
|
|
"Path not found"
|
|
);
|
|
}
|
|
|
|
// Initialize behavior analysis
|
|
var analysis = new BehaviorAnalysis
|
|
{
|
|
AnalysisPath = path,
|
|
SpecificationPath = specificationPath ?? string.Empty,
|
|
AnalysisDate = DateTime.UtcNow,
|
|
BehaviorSummaries = new List<BehaviorSummary>(),
|
|
SpecificationAlignments = new List<SpecificationAlignment>(),
|
|
SemanticDrifts = new List<SemanticDrift>(),
|
|
BreakingChanges = new List<BreakingChange>(),
|
|
TestSuggestions = new List<BehaviorTestSuggestion>(),
|
|
IntentValidations = new List<IntentValidation>()
|
|
};
|
|
|
|
// Discover and analyze code files
|
|
await DiscoverAndAnalyzeCode(path, analysis);
|
|
|
|
// Load and analyze specifications
|
|
if (!string.IsNullOrEmpty(specificationPath) && File.Exists(specificationPath))
|
|
{
|
|
await AnalyzeSpecifications(specificationPath, analysis);
|
|
}
|
|
|
|
// Generate behavior summaries
|
|
if (generateSummaries)
|
|
{
|
|
await GenerateBehaviorSummaries(analysis);
|
|
}
|
|
|
|
// Compare with previous versions
|
|
if (compareVersions)
|
|
{
|
|
await CompareWithPreviousVersions(analysis);
|
|
}
|
|
|
|
// Detect breaking changes
|
|
if (detectBreakingChanges)
|
|
{
|
|
await DetectBreakingChangesMethod(analysis);
|
|
}
|
|
|
|
// Validate intent alignment
|
|
if (validateIntent)
|
|
{
|
|
await ValidateIntentAlignment(analysis);
|
|
}
|
|
|
|
// Generate test suggestions
|
|
if (suggestTests)
|
|
{
|
|
await GenerateBehaviorTestSuggestions(analysis);
|
|
}
|
|
|
|
// Calculate behavior health score
|
|
var behaviorScore = CalculateBehaviorScore(analysis);
|
|
|
|
var result = new
|
|
{
|
|
Path = path,
|
|
SpecificationPath = specificationPath,
|
|
AnalysisDate = analysis.AnalysisDate,
|
|
BehaviorScore = behaviorScore,
|
|
CodeStructure = new
|
|
{
|
|
TotalClasses = analysis.AnalyzedClasses.Count,
|
|
TotalMethods = analysis.AnalyzedMethods.Count,
|
|
PublicAPIs = analysis.AnalyzedMethods.Count(m => m.IsPublic),
|
|
BusinessLogicMethods = analysis.AnalyzedMethods.Count(m => m.HasBusinessLogic)
|
|
},
|
|
BehaviorSummary = generateSummaries && analysis.BehaviorSummaries.Any() ?
|
|
analysis.BehaviorSummaries.First().Summary :
|
|
"Behavior summary generation was disabled or no summaries generated",
|
|
SpecificationAlignment = validateIntent && !string.IsNullOrEmpty(specificationPath) ?
|
|
analysis.SpecificationAlignments.Select(s => new
|
|
{
|
|
s.Component,
|
|
s.SpecificationRequirement,
|
|
s.ActualBehavior,
|
|
s.AlignmentLevel,
|
|
s.Discrepancies,
|
|
s.Recommendations
|
|
}).ToList() : null,
|
|
SemanticDrift = compareVersions ? analysis.SemanticDrifts.Select(d => new
|
|
{
|
|
d.Component,
|
|
d.DriftType,
|
|
d.Description,
|
|
d.Severity,
|
|
d.Impact,
|
|
d.Recommendation,
|
|
d.DetectedAt
|
|
}).ToList() : null,
|
|
BreakingChanges = detectBreakingChanges ? analysis.BreakingChanges.Select(b => new
|
|
{
|
|
b.ChangeType,
|
|
b.Component,
|
|
b.Description,
|
|
b.Impact,
|
|
b.Severity,
|
|
b.MitigationStrategy,
|
|
b.AffectedAPIs
|
|
}).ToList() : null,
|
|
TestSuggestions = suggestTests ? analysis.TestSuggestions.Select(t => new
|
|
{
|
|
t.TestType,
|
|
t.TargetComponent,
|
|
t.BehaviorToTest,
|
|
t.TestScenario,
|
|
t.Priority,
|
|
t.Rationale,
|
|
t.Implementation
|
|
}).OrderByDescending(t => t.Priority).ToList() : null,
|
|
IntentValidation = validateIntent ? new
|
|
{
|
|
OverallAlignment = analysis.IntentValidations.Any() ?
|
|
analysis.IntentValidations.Average(i => i.AlignmentScore) : 0,
|
|
ValidatedComponents = analysis.IntentValidations.Count,
|
|
HighAlignmentComponents = analysis.IntentValidations.Count(i => i.AlignmentScore >= 80),
|
|
LowAlignmentComponents = analysis.IntentValidations.Count(i => i.AlignmentScore < 60),
|
|
KeyFindings = analysis.IntentValidations
|
|
.Where(i => i.AlignmentScore < 70)
|
|
.Select(i => $"{i.Component}: {i.Finding}")
|
|
.Take(5)
|
|
.ToList()
|
|
} : null,
|
|
Summary = new
|
|
{
|
|
OverallBehaviorHealth = GetBehaviorHealth(behaviorScore),
|
|
CriticalIssues = analysis.BreakingChanges.Count(b => b.Severity == "High") +
|
|
analysis.SemanticDrifts.Count(d => d.Severity == "High"),
|
|
SpecificationCompliance = analysis.SpecificationAlignments.Any() ?
|
|
$"{analysis.SpecificationAlignments.Count(s => s.AlignmentLevel >= 80)}/{analysis.SpecificationAlignments.Count} components aligned" :
|
|
"No specifications provided",
|
|
TopRecommendations = GetTopBehaviorRecommendations(analysis),
|
|
BehaviorComplexity = GetBehaviorComplexity(analysis)
|
|
}
|
|
};
|
|
|
|
return new AIPluginResult(result,
|
|
$"Behavior analysis completed. Score: {behaviorScore}/100. " +
|
|
$"Analyzed {analysis.AnalyzedMethods.Count} methods across {analysis.AnalyzedClasses.Count} classes.");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return new AIPluginResult(ex, "Failed to analyze code behavior");
|
|
}
|
|
}
|
|
|
|
private Task DetectBreakingChangesMethod(BehaviorAnalysis analysis)
|
|
{
|
|
foreach (var method in analysis.AnalyzedMethods.Where(m => m.IsPublic))
|
|
{
|
|
var breakingChanges = AnalyzeMethodForBreakingChanges(method);
|
|
analysis.BreakingChanges.AddRange(breakingChanges);
|
|
}
|
|
|
|
foreach (var classInfo in analysis.AnalyzedClasses.Where(c => c.IsPublic))
|
|
{
|
|
var breakingChanges = AnalyzeClassForBreakingChanges(classInfo);
|
|
analysis.BreakingChanges.AddRange(breakingChanges);
|
|
}
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private async Task DiscoverAndAnalyzeCode(string path, BehaviorAnalysis analysis)
|
|
{
|
|
var files = GetFilesToAnalyze(path);
|
|
|
|
foreach (var filePath in files)
|
|
{
|
|
var sourceCode = await File.ReadAllTextAsync(filePath);
|
|
var syntaxTree = CSharpSyntaxTree.ParseText(sourceCode, path: filePath);
|
|
var root = await syntaxTree.GetRootAsync();
|
|
|
|
// Analyze classes
|
|
var classes = root.DescendantNodes().OfType<ClassDeclarationSyntax>();
|
|
foreach (var cls in classes)
|
|
{
|
|
var classInfo = AnalyzeClassBehavior(cls, filePath);
|
|
analysis.AnalyzedClasses.Add(classInfo);
|
|
}
|
|
|
|
// Analyze methods
|
|
var methods = root.DescendantNodes().OfType<MethodDeclarationSyntax>();
|
|
foreach (var method in methods)
|
|
{
|
|
var methodInfo = AnalyzeMethodBehavior(method, filePath);
|
|
analysis.AnalyzedMethods.Add(methodInfo);
|
|
}
|
|
}
|
|
}
|
|
|
|
private ClassBehaviorInfo AnalyzeClassBehavior(ClassDeclarationSyntax cls, string filePath)
|
|
{
|
|
var className = cls.Identifier.ValueText;
|
|
var namespaceName = GetNamespace(cls);
|
|
|
|
return new ClassBehaviorInfo
|
|
{
|
|
Name = className,
|
|
FullName = $"{namespaceName}.{className}",
|
|
Namespace = namespaceName,
|
|
FilePath = filePath,
|
|
IsPublic = cls.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword)),
|
|
IsAbstract = cls.Modifiers.Any(m => m.IsKind(SyntaxKind.AbstractKeyword)),
|
|
BaseTypes = cls.BaseList?.Types.Select(t => t.Type.ToString()).ToList() ?? new List<string>(),
|
|
Responsibilities = ExtractClassResponsibilities(cls),
|
|
DesignPatterns = DetectDesignPatterns(cls),
|
|
BehaviorCategory = DetermineBehaviorCategory(cls),
|
|
ComplexityIndicators = AnalyzeClassComplexity(cls)
|
|
};
|
|
}
|
|
|
|
private MethodBehaviorInfo AnalyzeMethodBehavior(MethodDeclarationSyntax method, string filePath)
|
|
{
|
|
var className = GetContainingClassName(method);
|
|
var methodName = method.Identifier.ValueText;
|
|
|
|
return new MethodBehaviorInfo
|
|
{
|
|
Name = methodName,
|
|
ClassName = className,
|
|
FilePath = filePath,
|
|
LineNumber = method.GetLocation().GetLineSpan().StartLinePosition.Line + 1,
|
|
IsPublic = method.Modifiers.Any(m => m.IsKind(SyntaxKind.PublicKeyword)),
|
|
IsAsync = method.Modifiers.Any(m => m.IsKind(SyntaxKind.AsyncKeyword)),
|
|
ReturnType = method.ReturnType.ToString(),
|
|
Parameters = ExtractParameterInfo(method),
|
|
BehaviorType = DetermineBehaviorType(method),
|
|
SideEffects = AnalyzeSideEffects(method),
|
|
Preconditions = ExtractPreconditions(method),
|
|
Postconditions = ExtractPostconditions(method),
|
|
BusinessRules = ExtractBusinessRules(method),
|
|
HasBusinessLogic = HasBusinessLogic(method),
|
|
DataFlow = AnalyzeDataFlow(method),
|
|
ControlFlow = AnalyzeControlFlow(method)
|
|
};
|
|
}
|
|
|
|
private async Task AnalyzeSpecifications(string specificationPath, BehaviorAnalysis analysis)
|
|
{
|
|
var specContent = await File.ReadAllTextAsync(specificationPath);
|
|
var requirements = ParseSpecificationRequirements(specContent);
|
|
|
|
analysis.SpecificationRequirements = requirements;
|
|
}
|
|
|
|
private Task GenerateBehaviorSummaries(BehaviorAnalysis analysis)
|
|
{
|
|
// Generate overall system behavior summary
|
|
var systemSummary = new BehaviorSummary
|
|
{
|
|
Component = "System",
|
|
BehaviorType = "Overall",
|
|
Summary = GenerateSystemBehaviorSummary(analysis),
|
|
KeyBehaviors = ExtractKeySystemBehaviors(analysis),
|
|
ComplexityLevel = GetComplexityLevel(CalculateSystemComplexity(analysis)),
|
|
BusinessValue = AssessBusinessValue(analysis)
|
|
};
|
|
|
|
analysis.BehaviorSummaries.Add(systemSummary);
|
|
|
|
// Generate class-level summaries for key classes
|
|
var keyClasses = analysis.AnalyzedClasses
|
|
.Where(c => c.IsPublic || c.BehaviorCategory == "BusinessLogic")
|
|
.Take(10);
|
|
|
|
foreach (var classInfo in keyClasses)
|
|
{
|
|
var classSummary = new BehaviorSummary
|
|
{
|
|
Component = classInfo.Name,
|
|
BehaviorType = "Class",
|
|
Summary = GenerateClassBehaviorSummary(classInfo, analysis),
|
|
KeyBehaviors = ExtractClassKeyBehaviors(classInfo, analysis),
|
|
ComplexityLevel = GetComplexityLevel(classInfo.ComplexityIndicators.GetValueOrDefault("CyclomaticComplexity", 0)),
|
|
BusinessValue = AssessClassBusinessValue(classInfo)
|
|
};
|
|
|
|
analysis.BehaviorSummaries.Add(classSummary);
|
|
}
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private async Task CompareWithPreviousVersions(BehaviorAnalysis analysis)
|
|
{
|
|
// Load previous analysis if available
|
|
var previousAnalysisPath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(analysis.AnalysisPath) ?? string.Empty, ".behavior-history.json");
|
|
|
|
if (File.Exists(previousAnalysisPath))
|
|
{
|
|
try
|
|
{
|
|
var previousData = await File.ReadAllTextAsync(previousAnalysisPath);
|
|
var previousAnalysis = JsonSerializer.Deserialize<BehaviorSnapshot>(previousData);
|
|
|
|
if (previousAnalysis != null)
|
|
{
|
|
DetectSemanticDrift(analysis, previousAnalysis);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// Ignore errors loading previous analysis
|
|
}
|
|
}
|
|
|
|
// Save current analysis for future comparison
|
|
await SaveBehaviorSnapshot(analysis, previousAnalysisPath);
|
|
}
|
|
|
|
private Task ValidateIntentAlignment(BehaviorAnalysis analysis)
|
|
{
|
|
foreach (var method in analysis.AnalyzedMethods)
|
|
{
|
|
var validation = ValidateMethodIntent(method, analysis.SpecificationRequirements);
|
|
analysis.IntentValidations.Add(validation);
|
|
}
|
|
|
|
foreach (var classInfo in analysis.AnalyzedClasses)
|
|
{
|
|
var validation = ValidateClassIntent(classInfo, analysis.SpecificationRequirements);
|
|
analysis.IntentValidations.Add(validation);
|
|
}
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private Task GenerateBehaviorTestSuggestions(BehaviorAnalysis analysis)
|
|
{
|
|
foreach (var method in analysis.AnalyzedMethods)
|
|
{
|
|
var suggestions = GenerateMethodTestSuggestions(method);
|
|
analysis.TestSuggestions.AddRange(suggestions);
|
|
}
|
|
|
|
// Generate integration test suggestions
|
|
var integrationSuggestions = GenerateIntegrationTestSuggestions(analysis);
|
|
analysis.TestSuggestions.AddRange(integrationSuggestions);
|
|
|
|
// Generate behavior-driven test suggestions
|
|
var bddSuggestions = GenerateBDDTestSuggestions(analysis);
|
|
analysis.TestSuggestions.AddRange(bddSuggestions);
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
// Helper methods for behavior analysis
|
|
private List<string> GetFilesToAnalyze(string path)
|
|
{
|
|
var files = new List<string>();
|
|
|
|
if (File.Exists(path) && path.EndsWith(".cs"))
|
|
{
|
|
files.Add(path);
|
|
}
|
|
else if (Directory.Exists(path))
|
|
{
|
|
files.AddRange(Directory.GetFiles(path, "*.cs", SearchOption.AllDirectories)
|
|
.Where(f => !f.Contains("\\bin\\") && !f.Contains("\\obj\\") &&
|
|
!f.EndsWith(".Designer.cs") && !f.EndsWith(".g.cs")));
|
|
}
|
|
|
|
return files;
|
|
}
|
|
|
|
private string GetNamespace(SyntaxNode node)
|
|
{
|
|
var namespaceDecl = node.Ancestors().OfType<NamespaceDeclarationSyntax>().FirstOrDefault();
|
|
return namespaceDecl?.Name.ToString() ?? "Global";
|
|
}
|
|
|
|
private string GetContainingClassName(SyntaxNode node)
|
|
{
|
|
var classDeclaration = node.Ancestors().OfType<ClassDeclarationSyntax>().FirstOrDefault();
|
|
return classDeclaration?.Identifier.ValueText ?? "Unknown";
|
|
}
|
|
|
|
private List<string> ExtractClassResponsibilities(ClassDeclarationSyntax cls)
|
|
{
|
|
var responsibilities = new List<string>();
|
|
|
|
// Analyze method names to infer responsibilities
|
|
var methods = cls.DescendantNodes().OfType<MethodDeclarationSyntax>();
|
|
|
|
var methodGroups = methods
|
|
.GroupBy(m => GetMethodCategory(m.Identifier.ValueText))
|
|
.Where(g => g.Key != "Unknown");
|
|
|
|
foreach (var group in methodGroups)
|
|
{
|
|
responsibilities.Add($"{group.Key} operations ({group.Count()} methods)");
|
|
}
|
|
|
|
// Analyze properties for data responsibilities
|
|
var properties = cls.DescendantNodes().OfType<PropertyDeclarationSyntax>();
|
|
if (properties.Any())
|
|
{
|
|
responsibilities.Add($"Data management ({properties.Count()} properties)");
|
|
}
|
|
|
|
return responsibilities;
|
|
}
|
|
|
|
private List<string> DetectDesignPatterns(ClassDeclarationSyntax cls)
|
|
{
|
|
var patterns = new List<string>();
|
|
var className = cls.Identifier.ValueText;
|
|
|
|
// Pattern detection based on naming and structure
|
|
if (className.EndsWith("Factory")) patterns.Add("Factory Pattern");
|
|
if (className.EndsWith("Builder")) patterns.Add("Builder Pattern");
|
|
if (className.EndsWith("Observer")) patterns.Add("Observer Pattern");
|
|
if (className.EndsWith("Strategy")) patterns.Add("Strategy Pattern");
|
|
if (className.EndsWith("Command")) patterns.Add("Command Pattern");
|
|
if (className.EndsWith("Facade")) patterns.Add("Facade Pattern");
|
|
if (className.EndsWith("Adapter")) patterns.Add("Adapter Pattern");
|
|
if (className.EndsWith("Repository")) patterns.Add("Repository Pattern");
|
|
if (className.EndsWith("Service")) patterns.Add("Service Pattern");
|
|
|
|
// Singleton pattern detection
|
|
var constructors = cls.DescendantNodes().OfType<ConstructorDeclarationSyntax>();
|
|
if (constructors.Any(c => c.Modifiers.Any(m => m.IsKind(SyntaxKind.PrivateKeyword))))
|
|
{
|
|
var fields = cls.DescendantNodes().OfType<FieldDeclarationSyntax>();
|
|
if (fields.Any(f => f.Modifiers.Any(m => m.IsKind(SyntaxKind.StaticKeyword))))
|
|
{
|
|
patterns.Add("Singleton Pattern");
|
|
}
|
|
}
|
|
|
|
return patterns;
|
|
}
|
|
|
|
private string DetermineBehaviorCategory(ClassDeclarationSyntax cls)
|
|
{
|
|
var className = cls.Identifier.ValueText.ToLowerInvariant();
|
|
var methods = cls.DescendantNodes().OfType<MethodDeclarationSyntax>();
|
|
|
|
if (className.Contains("controller")) return "Presentation";
|
|
if (className.Contains("service")) return "BusinessLogic";
|
|
if (className.Contains("repository") || className.Contains("dao")) return "DataAccess";
|
|
if (className.Contains("model") || className.Contains("entity")) return "Domain";
|
|
if (className.Contains("dto") || className.Contains("request") || className.Contains("response")) return "DataTransfer";
|
|
if (className.Contains("helper") || className.Contains("util")) return "Utility";
|
|
|
|
// Analyze method patterns
|
|
var businessMethods = methods.Count(m => HasBusinessLogic(m));
|
|
var dataMethods = methods.Count(m => AccessesData(m));
|
|
|
|
if (businessMethods > methods.Count() * 0.6) return "BusinessLogic";
|
|
if (dataMethods > methods.Count() * 0.5) return "DataAccess";
|
|
|
|
return "General";
|
|
}
|
|
|
|
private Dictionary<string, int> AnalyzeClassComplexity(ClassDeclarationSyntax cls)
|
|
{
|
|
var metrics = new Dictionary<string, int>();
|
|
|
|
var methods = cls.DescendantNodes().OfType<MethodDeclarationSyntax>();
|
|
var properties = cls.DescendantNodes().OfType<PropertyDeclarationSyntax>();
|
|
|
|
metrics["MethodCount"] = methods.Count();
|
|
metrics["PropertyCount"] = properties.Count();
|
|
metrics["CyclomaticComplexity"] = methods.Sum(m => CalculateMethodComplexity(m));
|
|
metrics["Responsibilities"] = ExtractClassResponsibilities(cls).Count;
|
|
metrics["Dependencies"] = ExtractClassDependencies(cls).Count;
|
|
|
|
return metrics;
|
|
}
|
|
|
|
private List<ParameterInfo> ExtractParameterInfo(MethodDeclarationSyntax method)
|
|
{
|
|
return method.ParameterList.Parameters.Select(p => new ParameterInfo
|
|
{
|
|
Name = p.Identifier.ValueText,
|
|
Type = p.Type?.ToString() ?? "unknown",
|
|
HasDefaultValue = p.Default != null,
|
|
IsOptional = p.Modifiers.Any(m => m.IsKind(SyntaxKind.ParamsKeyword))
|
|
}).ToList();
|
|
}
|
|
|
|
private string DetermineBehaviorType(MethodDeclarationSyntax method)
|
|
{
|
|
var methodName = method.Identifier.ValueText.ToLowerInvariant();
|
|
var returnType = method.ReturnType.ToString().ToLowerInvariant();
|
|
|
|
if (methodName.StartsWith("get") || methodName.StartsWith("retrieve")) return "Query";
|
|
if (methodName.StartsWith("set") || methodName.StartsWith("update") || methodName.StartsWith("save")) return "Command";
|
|
if (methodName.StartsWith("create") || methodName.StartsWith("add")) return "Creation";
|
|
if (methodName.StartsWith("delete") || methodName.StartsWith("remove")) return "Deletion";
|
|
if (methodName.StartsWith("validate") || methodName.StartsWith("check")) return "Validation";
|
|
if (methodName.StartsWith("calculate") || methodName.StartsWith("compute")) return "Computation";
|
|
if (methodName.StartsWith("process") || methodName.StartsWith("handle")) return "Processing";
|
|
if (returnType == "bool" || methodName.StartsWith("is") || methodName.StartsWith("has")) return "Predicate";
|
|
|
|
return "General";
|
|
}
|
|
|
|
private List<string> AnalyzeSideEffects(MethodDeclarationSyntax method)
|
|
{
|
|
var sideEffects = new List<string>();
|
|
var methodBody = method.Body?.ToString() ?? method.ExpressionBody?.ToString() ?? "";
|
|
|
|
if (methodBody.Contains("Console.Write") || methodBody.Contains("Console.Out"))
|
|
sideEffects.Add("Console Output");
|
|
|
|
if (methodBody.Contains("File.") || methodBody.Contains("Directory."))
|
|
sideEffects.Add("File System Access");
|
|
|
|
if (methodBody.Contains("HttpClient") || methodBody.Contains("WebRequest"))
|
|
sideEffects.Add("Network Communication");
|
|
|
|
if (methodBody.Contains("Database") || methodBody.Contains("Connection") || methodBody.Contains("Command"))
|
|
sideEffects.Add("Database Modification");
|
|
|
|
// Check for field modifications
|
|
var assignments = method.DescendantNodes().OfType<AssignmentExpressionSyntax>();
|
|
if (assignments.Any(a => !IsLocalVariable(a.Left)))
|
|
sideEffects.Add("State Modification");
|
|
|
|
if (method.Modifiers.Any(m => m.IsKind(SyntaxKind.AsyncKeyword)))
|
|
sideEffects.Add("Asynchronous Operation");
|
|
|
|
return sideEffects;
|
|
}
|
|
|
|
private List<string> ExtractPreconditions(MethodDeclarationSyntax method)
|
|
{
|
|
var preconditions = new List<string>();
|
|
|
|
// Look for parameter validation
|
|
var throwStatements = method.DescendantNodes().OfType<ThrowStatementSyntax>();
|
|
foreach (var throwStmt in throwStatements)
|
|
{
|
|
var condition = ExtractConditionFromThrow(throwStmt);
|
|
if (!string.IsNullOrEmpty(condition))
|
|
{
|
|
preconditions.Add(condition);
|
|
}
|
|
}
|
|
|
|
// Look for guard clauses
|
|
var ifStatements = method.DescendantNodes().OfType<IfStatementSyntax>().Take(3); // First few conditions are likely guards
|
|
foreach (var ifStmt in ifStatements)
|
|
{
|
|
if (IsGuardClause(ifStmt))
|
|
{
|
|
preconditions.Add($"Guard: {ifStmt.Condition}");
|
|
}
|
|
}
|
|
|
|
return preconditions;
|
|
}
|
|
|
|
private List<string> ExtractPostconditions(MethodDeclarationSyntax method)
|
|
{
|
|
var postconditions = new List<string>();
|
|
var returnType = method.ReturnType.ToString();
|
|
|
|
// Analyze return statements
|
|
var returnStatements = method.DescendantNodes().OfType<ReturnStatementSyntax>();
|
|
if (returnStatements.Any() && returnType != "void")
|
|
{
|
|
postconditions.Add($"Returns: {returnType}");
|
|
}
|
|
|
|
// Look for assertions or validation at method end
|
|
var lastStatements = GetLastStatements(method, 3);
|
|
foreach (var stmt in lastStatements)
|
|
{
|
|
if (IsPostconditionCheck(stmt))
|
|
{
|
|
postconditions.Add($"Ensures: {stmt}");
|
|
}
|
|
}
|
|
|
|
return postconditions;
|
|
}
|
|
|
|
private List<string> ExtractBusinessRules(MethodDeclarationSyntax method)
|
|
{
|
|
var businessRules = new List<string>();
|
|
|
|
// Look for business logic patterns
|
|
var ifStatements = method.DescendantNodes().OfType<IfStatementSyntax>();
|
|
foreach (var ifStmt in ifStatements)
|
|
{
|
|
if (IsBusinessRule(ifStmt))
|
|
{
|
|
businessRules.Add($"Rule: {SimplifyCondition(ifStmt.Condition.ToString())}");
|
|
}
|
|
}
|
|
|
|
// Look for switch statements (often business rules)
|
|
var switchStatements = method.DescendantNodes().OfType<SwitchStatementSyntax>();
|
|
foreach (var switchStmt in switchStatements)
|
|
{
|
|
businessRules.Add($"Business Logic Switch: {switchStmt.Expression}");
|
|
}
|
|
|
|
return businessRules;
|
|
}
|
|
|
|
private bool HasBusinessLogic(MethodDeclarationSyntax method)
|
|
{
|
|
var methodName = method.Identifier.ValueText.ToLowerInvariant();
|
|
var businessKeywords = new[] { "calculate", "process", "validate", "execute", "handle", "manage", "apply", "determine" };
|
|
|
|
if (businessKeywords.Any(keyword => methodName.Contains(keyword)))
|
|
return true;
|
|
|
|
// Check for complex logic
|
|
var complexity = CalculateMethodComplexity(method);
|
|
return complexity > 5;
|
|
}
|
|
|
|
private List<string> AnalyzeDataFlow(MethodDeclarationSyntax method)
|
|
{
|
|
var dataFlow = new List<string>();
|
|
|
|
var parameters = method.ParameterList.Parameters;
|
|
var returnType = method.ReturnType.ToString();
|
|
|
|
if (parameters.Any())
|
|
{
|
|
dataFlow.Add($"Input: {string.Join(", ", parameters.Select(p => p.Type))}");
|
|
}
|
|
|
|
if (returnType != "void")
|
|
{
|
|
dataFlow.Add($"Output: {returnType}");
|
|
}
|
|
|
|
// Analyze intermediate data transformations
|
|
var variableDeclarations = method.DescendantNodes().OfType<VariableDeclarationSyntax>();
|
|
var transformations = variableDeclarations.Count();
|
|
|
|
if (transformations > 0)
|
|
{
|
|
dataFlow.Add($"Transformations: {transformations} intermediate variables");
|
|
}
|
|
|
|
return dataFlow;
|
|
}
|
|
|
|
private List<string> AnalyzeControlFlow(MethodDeclarationSyntax method)
|
|
{
|
|
var controlFlow = new List<string>();
|
|
|
|
var ifStatements = method.DescendantNodes().OfType<IfStatementSyntax>().Count();
|
|
var loops = method.DescendantNodes().OfType<ForStatementSyntax>().Count() +
|
|
method.DescendantNodes().OfType<WhileStatementSyntax>().Count() +
|
|
method.DescendantNodes().OfType<ForEachStatementSyntax>().Count();
|
|
var switches = method.DescendantNodes().OfType<SwitchStatementSyntax>().Count();
|
|
var tryCatch = method.DescendantNodes().OfType<TryStatementSyntax>().Count();
|
|
|
|
if (ifStatements > 0) controlFlow.Add($"Conditional: {ifStatements} if statements");
|
|
if (loops > 0) controlFlow.Add($"Iterative: {loops} loops");
|
|
if (switches > 0) controlFlow.Add($"Selection: {switches} switch statements");
|
|
if (tryCatch > 0) controlFlow.Add($"Exception Handling: {tryCatch} try-catch blocks");
|
|
|
|
var complexity = CalculateMethodComplexity(method);
|
|
controlFlow.Add($"Cyclomatic Complexity: {complexity}");
|
|
|
|
return controlFlow;
|
|
}
|
|
|
|
private List<SpecificationRequirement> ParseSpecificationRequirements(string specContent)
|
|
{
|
|
var requirements = new List<SpecificationRequirement>();
|
|
|
|
// Simple parsing for common specification formats
|
|
var lines = specContent.Split('\n', StringSplitOptions.RemoveEmptyEntries);
|
|
|
|
foreach (var line in lines)
|
|
{
|
|
var trimmedLine = line.Trim();
|
|
|
|
// Look for requirement patterns
|
|
if (trimmedLine.StartsWith("REQ-") || trimmedLine.StartsWith("REQUIREMENT") ||
|
|
trimmedLine.Contains("SHALL") || trimmedLine.Contains("MUST"))
|
|
{
|
|
requirements.Add(new SpecificationRequirement
|
|
{
|
|
Id = ExtractRequirementId(trimmedLine),
|
|
Description = trimmedLine,
|
|
Priority = DetermineRequirementPriority(trimmedLine),
|
|
Category = DetermineRequirementCategory(trimmedLine)
|
|
});
|
|
}
|
|
}
|
|
|
|
return requirements;
|
|
}
|
|
|
|
private string GenerateSystemBehaviorSummary(BehaviorAnalysis analysis)
|
|
{
|
|
var summary = new List<string>();
|
|
|
|
summary.Add($"System contains {analysis.AnalyzedClasses.Count} classes and {analysis.AnalyzedMethods.Count} methods.");
|
|
|
|
var publicMethods = analysis.AnalyzedMethods.Count(m => m.IsPublic);
|
|
summary.Add($"Exposes {publicMethods} public methods as API surface.");
|
|
|
|
var behaviorCategories = analysis.AnalyzedClasses
|
|
.GroupBy(c => c.BehaviorCategory)
|
|
.ToDictionary(g => g.Key, g => g.Count());
|
|
|
|
summary.Add("Behavior distribution:");
|
|
foreach (var category in behaviorCategories)
|
|
{
|
|
summary.Add($" - {category.Key}: {category.Value} classes");
|
|
}
|
|
|
|
var businessLogicMethods = analysis.AnalyzedMethods.Count(m => m.HasBusinessLogic);
|
|
summary.Add($"Contains {businessLogicMethods} methods with business logic.");
|
|
|
|
return string.Join(" ", summary);
|
|
}
|
|
|
|
private List<string> ExtractKeySystemBehaviors(BehaviorAnalysis analysis)
|
|
{
|
|
var keyBehaviors = new List<string>();
|
|
|
|
// Extract most common behavior types
|
|
var behaviorTypes = analysis.AnalyzedMethods
|
|
.GroupBy(m => m.BehaviorType)
|
|
.OrderByDescending(g => g.Count())
|
|
.Take(5);
|
|
|
|
foreach (var behavior in behaviorTypes)
|
|
{
|
|
keyBehaviors.Add($"{behavior.Key} operations ({behavior.Count()} methods)");
|
|
}
|
|
|
|
// Extract key side effects
|
|
var sideEffects = analysis.AnalyzedMethods
|
|
.SelectMany(m => m.SideEffects)
|
|
.GroupBy(s => s)
|
|
.OrderByDescending(g => g.Count())
|
|
.Take(3);
|
|
|
|
foreach (var effect in sideEffects)
|
|
{
|
|
keyBehaviors.Add($"{effect.Key} ({effect.Count()} occurrences)");
|
|
}
|
|
|
|
return keyBehaviors;
|
|
}
|
|
|
|
private int CalculateSystemComplexity(BehaviorAnalysis analysis)
|
|
{
|
|
var totalComplexity = analysis.AnalyzedClasses.Sum(c =>
|
|
c.ComplexityIndicators.GetValueOrDefault("CyclomaticComplexity", 0));
|
|
|
|
var averageComplexity = analysis.AnalyzedClasses.Count > 0 ?
|
|
totalComplexity / analysis.AnalyzedClasses.Count : 0;
|
|
|
|
return averageComplexity;
|
|
}
|
|
|
|
private string AssessBusinessValue(BehaviorAnalysis analysis)
|
|
{
|
|
var businessLogicRatio = analysis.AnalyzedMethods.Count > 0 ?
|
|
(double)analysis.AnalyzedMethods.Count(m => m.HasBusinessLogic) / analysis.AnalyzedMethods.Count : 0;
|
|
|
|
if (businessLogicRatio > 0.6) return "High";
|
|
if (businessLogicRatio > 0.3) return "Medium";
|
|
return "Low";
|
|
}
|
|
|
|
private string GenerateClassBehaviorSummary(ClassBehaviorInfo classInfo, BehaviorAnalysis analysis)
|
|
{
|
|
var summary = new List<string>();
|
|
|
|
summary.Add($"{classInfo.Name} is a {classInfo.BehaviorCategory} class");
|
|
|
|
if (classInfo.Responsibilities.Any())
|
|
{
|
|
summary.Add($"with responsibilities: {string.Join(", ", classInfo.Responsibilities)}");
|
|
}
|
|
|
|
if (classInfo.DesignPatterns.Any())
|
|
{
|
|
summary.Add($"Implements: {string.Join(", ", classInfo.DesignPatterns)}");
|
|
}
|
|
|
|
var methodCount = analysis.AnalyzedMethods.Count(m => m.ClassName == classInfo.Name);
|
|
summary.Add($"Contains {methodCount} methods");
|
|
|
|
return string.Join(". ", summary);
|
|
}
|
|
|
|
private List<string> ExtractClassKeyBehaviors(ClassBehaviorInfo classInfo, BehaviorAnalysis analysis)
|
|
{
|
|
var keyBehaviors = new List<string>();
|
|
|
|
var classMethods = analysis.AnalyzedMethods.Where(m => m.ClassName == classInfo.Name);
|
|
|
|
// Group methods by behavior type
|
|
var behaviorGroups = classMethods
|
|
.GroupBy(m => m.BehaviorType)
|
|
.OrderByDescending(g => g.Count());
|
|
|
|
foreach (var group in behaviorGroups.Take(3))
|
|
{
|
|
keyBehaviors.Add($"{group.Key} ({group.Count()} methods)");
|
|
}
|
|
|
|
// Add significant side effects
|
|
var sideEffects = classMethods
|
|
.SelectMany(m => m.SideEffects)
|
|
.GroupBy(s => s)
|
|
.OrderByDescending(g => g.Count())
|
|
.Take(2);
|
|
|
|
foreach (var effect in sideEffects)
|
|
{
|
|
keyBehaviors.Add($"{effect.Key}");
|
|
}
|
|
|
|
return keyBehaviors;
|
|
}
|
|
|
|
private void DetectSemanticDrift(BehaviorAnalysis current, BehaviorSnapshot previous)
|
|
{
|
|
// Compare method signatures and behaviors
|
|
foreach (var currentMethod in current.AnalyzedMethods)
|
|
{
|
|
var previousMethod = previous.Methods.FirstOrDefault(m =>
|
|
m.Name == currentMethod.Name && m.ClassName == currentMethod.ClassName);
|
|
|
|
if (previousMethod != null)
|
|
{
|
|
var drifts = CompareMethodBehavior(currentMethod, previousMethod);
|
|
current.SemanticDrifts.AddRange(drifts);
|
|
}
|
|
}
|
|
|
|
// Compare class structures
|
|
foreach (var currentClass in current.AnalyzedClasses)
|
|
{
|
|
var previousClass = previous.Classes.FirstOrDefault(c => c.Name == currentClass.Name);
|
|
|
|
if (previousClass != null)
|
|
{
|
|
var drifts = CompareClassBehavior(currentClass, previousClass);
|
|
current.SemanticDrifts.AddRange(drifts);
|
|
}
|
|
}
|
|
}
|
|
|
|
private List<SemanticDrift> CompareMethodBehavior(MethodBehaviorInfo current, MethodSnapshot previous)
|
|
{
|
|
var drifts = new List<SemanticDrift>();
|
|
|
|
// Check behavior type changes
|
|
if (current.BehaviorType != previous.BehaviorType)
|
|
{
|
|
drifts.Add(new SemanticDrift
|
|
{
|
|
Component = $"{current.ClassName}.{current.Name}",
|
|
DriftType = "Behavior Type Change",
|
|
Description = $"Behavior changed from {previous.BehaviorType} to {current.BehaviorType}",
|
|
Severity = "Medium",
|
|
Impact = "Method semantics may have changed",
|
|
Recommendation = "Review method implementation and update documentation",
|
|
DetectedAt = DateTime.UtcNow
|
|
});
|
|
}
|
|
|
|
// Check side effects changes
|
|
var newSideEffects = current.SideEffects.Except(previous.SideEffects).ToList();
|
|
var removedSideEffects = previous.SideEffects.Except(current.SideEffects).ToList();
|
|
|
|
if (newSideEffects.Any())
|
|
{
|
|
drifts.Add(new SemanticDrift
|
|
{
|
|
Component = $"{current.ClassName}.{current.Name}",
|
|
DriftType = "New Side Effects",
|
|
Description = $"Added side effects: {string.Join(", ", newSideEffects)}",
|
|
Severity = "High",
|
|
Impact = "Method now has additional side effects",
|
|
Recommendation = "Ensure callers handle new side effects appropriately",
|
|
DetectedAt = DateTime.UtcNow
|
|
});
|
|
}
|
|
|
|
if (removedSideEffects.Any())
|
|
{
|
|
drifts.Add(new SemanticDrift
|
|
{
|
|
Component = $"{current.ClassName}.{current.Name}",
|
|
DriftType = "Removed Side Effects",
|
|
Description = $"Removed side effects: {string.Join(", ", removedSideEffects)}",
|
|
Severity = "Medium",
|
|
Impact = "Method no longer produces certain side effects",
|
|
Recommendation = "Verify that removed side effects are not needed",
|
|
DetectedAt = DateTime.UtcNow
|
|
});
|
|
}
|
|
|
|
return drifts;
|
|
}
|
|
|
|
private List<SemanticDrift> CompareClassBehavior(ClassBehaviorInfo current, ClassSnapshot previous)
|
|
{
|
|
var drifts = new List<SemanticDrift>();
|
|
|
|
// Check responsibility changes
|
|
var newResponsibilities = current.Responsibilities.Except(previous.Responsibilities).ToList();
|
|
var removedResponsibilities = previous.Responsibilities.Except(current.Responsibilities).ToList();
|
|
|
|
if (newResponsibilities.Any())
|
|
{
|
|
drifts.Add(new SemanticDrift
|
|
{
|
|
Component = current.Name,
|
|
DriftType = "New Responsibilities",
|
|
Description = $"Added responsibilities: {string.Join(", ", newResponsibilities)}",
|
|
Severity = "Medium",
|
|
Impact = "Class scope has expanded",
|
|
Recommendation = "Consider if class is becoming too complex",
|
|
DetectedAt = DateTime.UtcNow
|
|
});
|
|
}
|
|
|
|
return drifts;
|
|
}
|
|
|
|
private async Task SaveBehaviorSnapshot(BehaviorAnalysis analysis, string snapshotPath)
|
|
{
|
|
var snapshot = new BehaviorSnapshot
|
|
{
|
|
AnalysisDate = analysis.AnalysisDate,
|
|
Classes = analysis.AnalyzedClasses.Select(c => new ClassSnapshot
|
|
{
|
|
Name = c.Name,
|
|
BehaviorCategory = c.BehaviorCategory,
|
|
Responsibilities = c.Responsibilities,
|
|
DesignPatterns = c.DesignPatterns
|
|
}).ToList(),
|
|
Methods = analysis.AnalyzedMethods.Select(m => new MethodSnapshot
|
|
{
|
|
Name = m.Name,
|
|
ClassName = m.ClassName,
|
|
BehaviorType = m.BehaviorType,
|
|
SideEffects = m.SideEffects,
|
|
HasBusinessLogic = m.HasBusinessLogic
|
|
}).ToList()
|
|
};
|
|
|
|
try
|
|
{
|
|
var json = JsonSerializer.Serialize(snapshot, new JsonSerializerOptions { WriteIndented = true });
|
|
await File.WriteAllTextAsync(snapshotPath, json);
|
|
}
|
|
catch
|
|
{
|
|
// Ignore save errors
|
|
}
|
|
}
|
|
|
|
private List<BreakingChange> AnalyzeMethodForBreakingChanges(MethodBehaviorInfo method)
|
|
{
|
|
var breakingChanges = new List<BreakingChange>();
|
|
|
|
// Check for potential breaking changes based on method characteristics
|
|
if (method.SideEffects.Contains("Database Modification"))
|
|
{
|
|
breakingChanges.Add(new BreakingChange
|
|
{
|
|
ChangeType = "Data Modification",
|
|
Component = $"{method.ClassName}.{method.Name}",
|
|
Description = "Method modifies database state",
|
|
Impact = "Callers may experience data consistency issues",
|
|
Severity = "Medium",
|
|
MitigationStrategy = "Ensure proper transaction handling and rollback capabilities",
|
|
AffectedAPIs = new List<string> { $"{method.ClassName}.{method.Name}" }
|
|
});
|
|
}
|
|
|
|
if (method.SideEffects.Contains("Network Communication"))
|
|
{
|
|
breakingChanges.Add(new BreakingChange
|
|
{
|
|
ChangeType = "External Dependency",
|
|
Component = $"{method.ClassName}.{method.Name}",
|
|
Description = "Method depends on external network services",
|
|
Impact = "Method may fail due to network issues",
|
|
Severity = "Low",
|
|
MitigationStrategy = "Implement retry logic and graceful degradation",
|
|
AffectedAPIs = new List<string> { $"{method.ClassName}.{method.Name}" }
|
|
});
|
|
}
|
|
|
|
return breakingChanges;
|
|
}
|
|
|
|
private List<BreakingChange> AnalyzeClassForBreakingChanges(ClassBehaviorInfo classInfo)
|
|
{
|
|
var breakingChanges = new List<BreakingChange>();
|
|
|
|
// Check for inheritance changes
|
|
if (classInfo.BaseTypes.Any())
|
|
{
|
|
breakingChanges.Add(new BreakingChange
|
|
{
|
|
ChangeType = "Inheritance Structure",
|
|
Component = classInfo.Name,
|
|
Description = "Class has inheritance relationships that may constrain changes",
|
|
Impact = "Changes may affect derived classes",
|
|
Severity = "Medium",
|
|
MitigationStrategy = "Use interface segregation and dependency inversion",
|
|
AffectedAPIs = new List<string> { classInfo.Name }
|
|
});
|
|
}
|
|
|
|
return breakingChanges;
|
|
}
|
|
|
|
private IntentValidation ValidateMethodIntent(MethodBehaviorInfo method, List<SpecificationRequirement> requirements)
|
|
{
|
|
var validation = new IntentValidation
|
|
{
|
|
Component = $"{method.ClassName}.{method.Name}",
|
|
ComponentType = "Method",
|
|
ExpectedIntent = DetermineExpectedIntent(method),
|
|
ActualBehavior = DescribeActualBehavior(method),
|
|
AlignmentScore = CalculateAlignmentScore(method, requirements),
|
|
Finding = GenerateAlignmentFinding(method, requirements),
|
|
Recommendations = GenerateAlignmentRecommendations(method, requirements)
|
|
};
|
|
|
|
return validation;
|
|
}
|
|
|
|
private IntentValidation ValidateClassIntent(ClassBehaviorInfo classInfo, List<SpecificationRequirement> requirements)
|
|
{
|
|
var validation = new IntentValidation
|
|
{
|
|
Component = classInfo.Name,
|
|
ComponentType = "Class",
|
|
ExpectedIntent = $"Implement {classInfo.BehaviorCategory} functionality",
|
|
ActualBehavior = string.Join(", ", classInfo.Responsibilities),
|
|
AlignmentScore = CalculateClassAlignmentScore(classInfo, requirements),
|
|
Finding = GenerateClassAlignmentFinding(classInfo, requirements),
|
|
Recommendations = GenerateClassAlignmentRecommendations(classInfo)
|
|
};
|
|
|
|
return validation;
|
|
}
|
|
|
|
private List<BehaviorTestSuggestion> GenerateMethodTestSuggestions(MethodBehaviorInfo method)
|
|
{
|
|
var suggestions = new List<BehaviorTestSuggestion>();
|
|
|
|
// Basic behavior tests
|
|
suggestions.Add(new BehaviorTestSuggestion
|
|
{
|
|
TestType = "Behavior Verification",
|
|
TargetComponent = $"{method.ClassName}.{method.Name}",
|
|
BehaviorToTest = $"Method exhibits {method.BehaviorType} behavior correctly",
|
|
TestScenario = $"Given valid inputs, when {method.Name} is called, then it should perform {method.BehaviorType} operation",
|
|
Priority = method.IsPublic ? 8 : 5,
|
|
Rationale = $"Verify core {method.BehaviorType} behavior",
|
|
Implementation = GenerateTestImplementation(method)
|
|
});
|
|
|
|
// Side effect tests
|
|
foreach (var sideEffect in method.SideEffects)
|
|
{
|
|
suggestions.Add(new BehaviorTestSuggestion
|
|
{
|
|
TestType = "Side Effect Verification",
|
|
TargetComponent = $"{method.ClassName}.{method.Name}",
|
|
BehaviorToTest = $"Method produces {sideEffect} side effect correctly",
|
|
TestScenario = $"When {method.Name} is called, then {sideEffect} should occur as expected",
|
|
Priority = GetSideEffectTestPriority(sideEffect),
|
|
Rationale = $"Ensure {sideEffect} side effect is properly controlled",
|
|
Implementation = GenerateSideEffectTestImplementation(method, sideEffect)
|
|
});
|
|
}
|
|
|
|
// Business rule tests
|
|
foreach (var rule in method.BusinessRules)
|
|
{
|
|
suggestions.Add(new BehaviorTestSuggestion
|
|
{
|
|
TestType = "Business Rule Verification",
|
|
TargetComponent = $"{method.ClassName}.{method.Name}",
|
|
BehaviorToTest = $"Business rule implementation: {rule}",
|
|
TestScenario = $"Given business scenario, when rule applies, then {rule} should be enforced",
|
|
Priority = 9,
|
|
Rationale = "Business rules are critical for domain correctness",
|
|
Implementation = GenerateBusinessRuleTestImplementation(method, rule)
|
|
});
|
|
}
|
|
|
|
return suggestions;
|
|
}
|
|
|
|
private List<BehaviorTestSuggestion> GenerateIntegrationTestSuggestions(BehaviorAnalysis analysis)
|
|
{
|
|
var suggestions = new List<BehaviorTestSuggestion>();
|
|
|
|
// Find classes that interact with external systems
|
|
var externallyConnectedClasses = analysis.AnalyzedClasses
|
|
.Where(c => analysis.AnalyzedMethods
|
|
.Where(m => m.ClassName == c.Name)
|
|
.Any(m => m.SideEffects.Contains("Database Modification") ||
|
|
m.SideEffects.Contains("Network Communication")))
|
|
.ToList();
|
|
|
|
foreach (var cls in externallyConnectedClasses)
|
|
{
|
|
suggestions.Add(new BehaviorTestSuggestion
|
|
{
|
|
TestType = "Integration Test",
|
|
TargetComponent = cls.Name,
|
|
BehaviorToTest = "End-to-end integration with external systems",
|
|
TestScenario = $"Given real external dependencies, when {cls.Name} operations are performed, then integration should work correctly",
|
|
Priority = 7,
|
|
Rationale = "Verify integration points work correctly in realistic scenarios",
|
|
Implementation = $"Create integration tests with test containers or mock services for {cls.Name}"
|
|
});
|
|
}
|
|
|
|
return suggestions;
|
|
}
|
|
|
|
private List<BehaviorTestSuggestion> GenerateBDDTestSuggestions(BehaviorAnalysis analysis)
|
|
{
|
|
var suggestions = new List<BehaviorTestSuggestion>();
|
|
|
|
var businessLogicClasses = analysis.AnalyzedClasses
|
|
.Where(c => c.BehaviorCategory == "BusinessLogic")
|
|
.ToList();
|
|
|
|
foreach (var cls in businessLogicClasses)
|
|
{
|
|
suggestions.Add(new BehaviorTestSuggestion
|
|
{
|
|
TestType = "Behavior-Driven Test",
|
|
TargetComponent = cls.Name,
|
|
BehaviorToTest = "Business behavior from user perspective",
|
|
TestScenario = $"Given business context, when user performs action, then {cls.Name} should deliver expected business outcome",
|
|
Priority = 8,
|
|
Rationale = "Ensure business behavior matches stakeholder expectations",
|
|
Implementation = $"Create Gherkin scenarios for {cls.Name} business operations"
|
|
});
|
|
}
|
|
|
|
return suggestions;
|
|
}
|
|
|
|
// Utility and helper methods
|
|
private int CalculateMethodComplexity(MethodDeclarationSyntax method)
|
|
{
|
|
var complexity = 1;
|
|
var descendants = method.DescendantNodes();
|
|
|
|
complexity += descendants.OfType<IfStatementSyntax>().Count();
|
|
complexity += descendants.OfType<WhileStatementSyntax>().Count();
|
|
complexity += descendants.OfType<ForStatementSyntax>().Count();
|
|
complexity += descendants.OfType<ForEachStatementSyntax>().Count();
|
|
complexity += descendants.OfType<SwitchStatementSyntax>().Count();
|
|
complexity += descendants.OfType<CatchClauseSyntax>().Count();
|
|
|
|
return complexity;
|
|
}
|
|
|
|
private string GetMethodCategory(string methodName)
|
|
{
|
|
var name = methodName.ToLowerInvariant();
|
|
|
|
if (name.StartsWith("get") || name.StartsWith("retrieve") || name.StartsWith("find")) return "Data Retrieval";
|
|
if (name.StartsWith("set") || name.StartsWith("update") || name.StartsWith("save")) return "Data Modification";
|
|
if (name.StartsWith("create") || name.StartsWith("add") || name.StartsWith("insert")) return "Data Creation";
|
|
if (name.StartsWith("delete") || name.StartsWith("remove")) return "Data Deletion";
|
|
if (name.StartsWith("validate") || name.StartsWith("check") || name.StartsWith("verify")) return "Validation";
|
|
if (name.StartsWith("calculate") || name.StartsWith("compute")) return "Calculation";
|
|
if (name.StartsWith("process") || name.StartsWith("handle") || name.StartsWith("execute")) return "Processing";
|
|
|
|
return "Unknown";
|
|
}
|
|
|
|
private bool AccessesData(MethodDeclarationSyntax method)
|
|
{
|
|
var methodBody = method.Body?.ToString() ?? method.ExpressionBody?.ToString() ?? "";
|
|
var dataKeywords = new[] { "database", "repository", "entity", "dbcontext", "connection", "command", "query" };
|
|
return dataKeywords.Any(keyword => methodBody.ToLowerInvariant().Contains(keyword));
|
|
}
|
|
|
|
private List<string> ExtractClassDependencies(ClassDeclarationSyntax cls)
|
|
{
|
|
var dependencies = new HashSet<string>();
|
|
|
|
// Extract from field types
|
|
var fields = cls.DescendantNodes().OfType<FieldDeclarationSyntax>();
|
|
foreach (var field in fields)
|
|
{
|
|
dependencies.Add(field.Declaration.Type.ToString());
|
|
}
|
|
|
|
// Extract from property types
|
|
var properties = cls.DescendantNodes().OfType<PropertyDeclarationSyntax>();
|
|
foreach (var property in properties)
|
|
{
|
|
dependencies.Add(property.Type.ToString());
|
|
}
|
|
|
|
// Extract from constructor parameters
|
|
var constructors = cls.DescendantNodes().OfType<ConstructorDeclarationSyntax>();
|
|
foreach (var constructor in constructors)
|
|
{
|
|
foreach (var param in constructor.ParameterList.Parameters)
|
|
{
|
|
dependencies.Add(param.Type?.ToString() ?? "unknown");
|
|
}
|
|
}
|
|
|
|
return dependencies.Where(d => !string.IsNullOrEmpty(d) && !d.StartsWith("System.")).ToList();
|
|
}
|
|
|
|
private bool IsLocalVariable(ExpressionSyntax expression)
|
|
{
|
|
// Simple heuristic to determine if assignment target is a local variable
|
|
return expression is IdentifierNameSyntax identifier &&
|
|
char.IsLower(identifier.Identifier.ValueText[0]);
|
|
}
|
|
|
|
private string ExtractConditionFromThrow(ThrowStatementSyntax throwStmt)
|
|
{
|
|
var expression = throwStmt.Expression?.ToString() ?? "";
|
|
if (expression.Contains("ArgumentNullException")) return "Parameter must not be null";
|
|
if (expression.Contains("ArgumentException")) return "Parameter must be valid";
|
|
if (expression.Contains("InvalidOperationException")) return "Object must be in valid state";
|
|
return "Precondition check";
|
|
}
|
|
|
|
private bool IsGuardClause(IfStatementSyntax ifStmt)
|
|
{
|
|
// Check if if statement is likely a guard clause (early return/throw)
|
|
var statement = ifStmt.Statement;
|
|
return statement is ThrowStatementSyntax ||
|
|
(statement is BlockSyntax block &&
|
|
block.Statements.Count == 1 &&
|
|
(block.Statements[0] is ThrowStatementSyntax || block.Statements[0] is ReturnStatementSyntax));
|
|
}
|
|
|
|
private List<StatementSyntax> GetLastStatements(MethodDeclarationSyntax method, int count)
|
|
{
|
|
var statements = method.Body?.Statements ?? new SyntaxList<StatementSyntax>();
|
|
return statements.TakeLast(count).ToList();
|
|
}
|
|
|
|
private bool IsPostconditionCheck(StatementSyntax statement)
|
|
{
|
|
var statementText = statement.ToString().ToLowerInvariant();
|
|
return statementText.Contains("assert") || statementText.Contains("ensure") || statementText.Contains("contract");
|
|
}
|
|
|
|
private bool IsBusinessRule(IfStatementSyntax ifStmt)
|
|
{
|
|
var condition = ifStmt.Condition.ToString().ToLowerInvariant();
|
|
var businessIndicators = new[] { "status", "state", "type", "category", "amount", "count", "limit", "threshold" };
|
|
return businessIndicators.Any(indicator => condition.Contains(indicator));
|
|
}
|
|
|
|
private string SimplifyCondition(string condition)
|
|
{
|
|
// Simplify complex conditions for readability
|
|
if (condition.Length > 50)
|
|
{
|
|
return condition.Substring(0, 47) + "...";
|
|
}
|
|
return condition;
|
|
}
|
|
|
|
private string GetComplexityLevel(int complexity)
|
|
{
|
|
return complexity switch
|
|
{
|
|
<= 5 => "Low",
|
|
<= 10 => "Medium",
|
|
<= 20 => "High",
|
|
_ => "Very High"
|
|
};
|
|
}
|
|
|
|
private string AssessClassBusinessValue(ClassBehaviorInfo classInfo)
|
|
{
|
|
if (classInfo.BehaviorCategory == "BusinessLogic") return "High";
|
|
if (classInfo.BehaviorCategory == "Domain") return "High";
|
|
if (classInfo.BehaviorCategory == "Presentation") return "Medium";
|
|
if (classInfo.BehaviorCategory == "DataAccess") return "Medium";
|
|
return "Low";
|
|
}
|
|
|
|
private string ExtractRequirementId(string requirementText)
|
|
{
|
|
var match = Regex.Match(requirementText, @"REQ-\d+");
|
|
return match.Success ? match.Value : $"REQ-{Guid.NewGuid().ToString("N")[..8]}";
|
|
}
|
|
|
|
private string DetermineRequirementPriority(string requirementText)
|
|
{
|
|
var text = requirementText.ToLowerInvariant();
|
|
if (text.Contains("critical") || text.Contains("must")) return "High";
|
|
if (text.Contains("should") || text.Contains("important")) return "Medium";
|
|
return "Low";
|
|
}
|
|
|
|
private string DetermineRequirementCategory(string requirementText)
|
|
{
|
|
var text = requirementText.ToLowerInvariant();
|
|
if (text.Contains("performance") || text.Contains("speed")) return "Performance";
|
|
if (text.Contains("security") || text.Contains("authentication")) return "Security";
|
|
if (text.Contains("usability") || text.Contains("user")) return "Usability";
|
|
if (text.Contains("functional") || text.Contains("business")) return "Functional";
|
|
return "General";
|
|
}
|
|
|
|
private string DetermineExpectedIntent(MethodBehaviorInfo method)
|
|
{
|
|
return $"Perform {method.BehaviorType} operation with appropriate {string.Join(", ", method.SideEffects)} handling";
|
|
}
|
|
|
|
private string DescribeActualBehavior(MethodBehaviorInfo method)
|
|
{
|
|
var behaviors = new List<string> { $"{method.BehaviorType} operation" };
|
|
if (method.SideEffects.Any()) behaviors.Add($"Side effects: {string.Join(", ", method.SideEffects)}");
|
|
if (method.BusinessRules.Any()) behaviors.Add($"Business rules: {method.BusinessRules.Count}");
|
|
return string.Join("; ", behaviors);
|
|
}
|
|
|
|
private int CalculateAlignmentScore(MethodBehaviorInfo method, List<SpecificationRequirement> requirements)
|
|
{
|
|
// Simple scoring based on method characteristics
|
|
var score = 70; // Base score
|
|
|
|
if (method.HasBusinessLogic) score += 10;
|
|
if (method.Preconditions.Any()) score += 5;
|
|
if (method.Postconditions.Any()) score += 5;
|
|
if (method.BusinessRules.Any()) score += 10;
|
|
|
|
// Penalty for excessive side effects
|
|
if (method.SideEffects.Count > 3) score -= 10;
|
|
|
|
return Math.Max(0, Math.Min(100, score));
|
|
}
|
|
|
|
private string GenerateAlignmentFinding(MethodBehaviorInfo method, List<SpecificationRequirement> requirements)
|
|
{
|
|
if (method.HasBusinessLogic && method.BusinessRules.Any())
|
|
{
|
|
return "Method implements business logic with defined rules";
|
|
}
|
|
if (method.SideEffects.Count > 2)
|
|
{
|
|
return "Method has multiple side effects that may need review";
|
|
}
|
|
if (!method.Preconditions.Any() && method.Parameters.Any())
|
|
{
|
|
return "Method lacks input validation";
|
|
}
|
|
return "Method behavior appears aligned with expected patterns";
|
|
}
|
|
|
|
private List<string> GenerateAlignmentRecommendations(MethodBehaviorInfo method, List<SpecificationRequirement> requirements)
|
|
{
|
|
var recommendations = new List<string>();
|
|
|
|
if (!method.Preconditions.Any() && method.Parameters.Any())
|
|
{
|
|
recommendations.Add("Add input validation and precondition checks");
|
|
}
|
|
|
|
if (method.SideEffects.Count > 2)
|
|
{
|
|
recommendations.Add("Consider breaking method into smaller, more focused operations");
|
|
}
|
|
|
|
if (!method.BusinessRules.Any() && method.HasBusinessLogic)
|
|
{
|
|
recommendations.Add("Document business rules and make them more explicit");
|
|
}
|
|
|
|
return recommendations;
|
|
}
|
|
|
|
private int CalculateClassAlignmentScore(ClassBehaviorInfo classInfo, List<SpecificationRequirement> requirements)
|
|
{
|
|
var score = 70; // Base score
|
|
|
|
if (classInfo.DesignPatterns.Any()) score += 15;
|
|
if (classInfo.Responsibilities.Count <= 3) score += 10; // Single Responsibility
|
|
if (classInfo.ComplexityIndicators["CyclomaticComplexity"] < 50) score += 5;
|
|
|
|
return Math.Max(0, Math.Min(100, score));
|
|
}
|
|
|
|
private string GenerateClassAlignmentFinding(ClassBehaviorInfo classInfo, List<SpecificationRequirement> requirements)
|
|
{
|
|
if (classInfo.Responsibilities.Count > 5)
|
|
{
|
|
return "Class has many responsibilities and may violate Single Responsibility Principle";
|
|
}
|
|
if (classInfo.DesignPatterns.Any())
|
|
{
|
|
return $"Class implements recognized design patterns: {string.Join(", ", classInfo.DesignPatterns)}";
|
|
}
|
|
return "Class structure follows standard patterns";
|
|
}
|
|
|
|
private List<string> GenerateClassAlignmentRecommendations(ClassBehaviorInfo classInfo)
|
|
{
|
|
var recommendations = new List<string>();
|
|
|
|
if (classInfo.Responsibilities.Count > 5)
|
|
{
|
|
recommendations.Add("Consider splitting class to improve cohesion");
|
|
}
|
|
|
|
if (!classInfo.DesignPatterns.Any() && classInfo.ComplexityIndicators["MethodCount"] > 10)
|
|
{
|
|
recommendations.Add("Consider applying design patterns to improve structure");
|
|
}
|
|
|
|
return recommendations;
|
|
}
|
|
|
|
private string GenerateTestImplementation(MethodBehaviorInfo method)
|
|
{
|
|
return $"Create unit test for {method.Name} that verifies {method.BehaviorType} behavior with various input scenarios";
|
|
}
|
|
|
|
private int GetSideEffectTestPriority(string sideEffect)
|
|
{
|
|
return sideEffect switch
|
|
{
|
|
"Database Modification" => 9,
|
|
"Network Communication" => 8,
|
|
"File System Access" => 7,
|
|
"State Modification" => 6,
|
|
_ => 5
|
|
};
|
|
}
|
|
|
|
private string GenerateSideEffectTestImplementation(MethodBehaviorInfo method, string sideEffect)
|
|
{
|
|
return $"Create test that verifies {sideEffect} occurs correctly when {method.Name} is called";
|
|
}
|
|
|
|
private string GenerateBusinessRuleTestImplementation(MethodBehaviorInfo method, string rule)
|
|
{
|
|
return $"Create test scenarios that validate business rule: {rule}";
|
|
}
|
|
|
|
private int CalculateBehaviorScore(BehaviorAnalysis analysis)
|
|
{
|
|
var score = 100;
|
|
|
|
// Deduct for complexity issues
|
|
var avgComplexity = CalculateSystemComplexity(analysis);
|
|
if (avgComplexity > 20) score -= 20;
|
|
else if (avgComplexity > 10) score -= 10;
|
|
|
|
// Deduct for breaking changes
|
|
var criticalBreakingChanges = analysis.BreakingChanges.Count(b => b.Severity == "High");
|
|
score -= criticalBreakingChanges * 15;
|
|
|
|
// Deduct for semantic drift
|
|
var criticalDrifts = analysis.SemanticDrifts.Count(d => d.Severity == "High");
|
|
score -= criticalDrifts * 10;
|
|
|
|
// Bonus for good alignment
|
|
var avgAlignment = analysis.IntentValidations.Any() ?
|
|
analysis.IntentValidations.Average(i => i.AlignmentScore) : 70;
|
|
if (avgAlignment > 80) score += 10;
|
|
|
|
return Math.Max(0, Math.Min(100, score));
|
|
}
|
|
|
|
private string GetBehaviorHealth(int score)
|
|
{
|
|
return score switch
|
|
{
|
|
>= 80 => "Excellent",
|
|
>= 60 => "Good",
|
|
>= 40 => "Fair",
|
|
>= 20 => "Poor",
|
|
_ => "Critical"
|
|
};
|
|
}
|
|
|
|
private string GetBehaviorComplexity(BehaviorAnalysis analysis)
|
|
{
|
|
var avgComplexity = CalculateSystemComplexity(analysis);
|
|
return avgComplexity switch
|
|
{
|
|
<= 5 => "Low",
|
|
<= 10 => "Moderate",
|
|
<= 20 => "High",
|
|
_ => "Very High"
|
|
};
|
|
}
|
|
|
|
private List<string> GetTopBehaviorRecommendations(BehaviorAnalysis analysis)
|
|
{
|
|
var recommendations = new List<string>();
|
|
|
|
var criticalBreaking = analysis.BreakingChanges.Count(b => b.Severity == "High");
|
|
if (criticalBreaking > 0)
|
|
{
|
|
recommendations.Add($"Address {criticalBreaking} critical breaking changes");
|
|
}
|
|
|
|
var criticalDrifts = analysis.SemanticDrifts.Count(d => d.Severity == "High");
|
|
if (criticalDrifts > 0)
|
|
{
|
|
recommendations.Add($"Review {criticalDrifts} critical semantic drifts");
|
|
}
|
|
|
|
var lowAlignmentComponents = analysis.IntentValidations.Count(i => i.AlignmentScore < 60);
|
|
if (lowAlignmentComponents > 0)
|
|
{
|
|
recommendations.Add($"Improve alignment for {lowAlignmentComponents} components");
|
|
}
|
|
|
|
var highComplexityClasses = analysis.AnalyzedClasses.Count(c =>
|
|
c.ComplexityIndicators.GetValueOrDefault("CyclomaticComplexity", 0) > 20);
|
|
if (highComplexityClasses > 0)
|
|
{
|
|
recommendations.Add($"Refactor {highComplexityClasses} high-complexity classes");
|
|
}
|
|
|
|
var highPriorityTests = analysis.TestSuggestions.Count(t => t.Priority >= 8);
|
|
if (highPriorityTests > 0)
|
|
{
|
|
recommendations.Add($"Implement {highPriorityTests} high-priority behavior tests");
|
|
}
|
|
|
|
if (!recommendations.Any())
|
|
{
|
|
recommendations.Add("Behavior analysis shows good alignment - continue maintaining standards");
|
|
}
|
|
|
|
return recommendations.Take(5).ToList();
|
|
}
|
|
|
|
private bool GetBoolParameter(IReadOnlyDictionary<string, object> parameters, string key, bool defaultValue)
|
|
{
|
|
return parameters.TryGetValue(key, out var value) ? Convert.ToBoolean(value) : defaultValue;
|
|
}
|
|
}
|
|
|
|
// Supporting data structures for behavior analysis
|
|
public class BehaviorAnalysis
|
|
{
|
|
public string AnalysisPath { get; set; } = string.Empty;
|
|
public string? SpecificationPath { get; set; }
|
|
public DateTime AnalysisDate { get; set; }
|
|
public List<ClassBehaviorInfo> AnalyzedClasses { get; set; } = new();
|
|
public List<MethodBehaviorInfo> AnalyzedMethods { get; set; } = new();
|
|
public List<SpecificationRequirement> SpecificationRequirements { get; set; } = new();
|
|
public List<BehaviorSummary> BehaviorSummaries { get; set; } = new();
|
|
public List<SpecificationAlignment> SpecificationAlignments { get; set; } = new();
|
|
public List<SemanticDrift> SemanticDrifts { get; set; } = new();
|
|
public List<BreakingChange> BreakingChanges { get; set; } = new();
|
|
public List<BehaviorTestSuggestion> TestSuggestions { get; set; } = new();
|
|
public List<IntentValidation> IntentValidations { get; set; } = new();
|
|
}
|
|
|
|
public class ClassBehaviorInfo
|
|
{
|
|
public string Name { get; set; } = string.Empty;
|
|
public string FullName { get; set; } = string.Empty;
|
|
public string Namespace { get; set; } = string.Empty;
|
|
public string FilePath { get; set; } = string.Empty;
|
|
public bool IsPublic { get; set; }
|
|
public bool IsAbstract { get; set; }
|
|
public List<string> BaseTypes { get; set; } = new();
|
|
public List<string> Responsibilities { get; set; } = new();
|
|
public List<string> DesignPatterns { get; set; } = new();
|
|
public string BehaviorCategory { get; set; } = string.Empty;
|
|
public Dictionary<string, int> ComplexityIndicators { get; set; } = new();
|
|
}
|
|
|
|
public class MethodBehaviorInfo
|
|
{
|
|
public string Name { get; set; } = string.Empty;
|
|
public string ClassName { get; set; } = string.Empty;
|
|
public string FilePath { get; set; } = string.Empty;
|
|
public int LineNumber { get; set; }
|
|
public bool IsPublic { get; set; }
|
|
public bool IsAsync { get; set; }
|
|
public string ReturnType { get; set; } = string.Empty;
|
|
public List<ParameterInfo> Parameters { get; set; } = new();
|
|
public string BehaviorType { get; set; } = string.Empty;
|
|
public List<string> SideEffects { get; set; } = new();
|
|
public List<string> Preconditions { get; set; } = new();
|
|
public List<string> Postconditions { get; set; } = new();
|
|
public List<string> BusinessRules { get; set; } = new();
|
|
public bool HasBusinessLogic { get; set; }
|
|
public List<string> DataFlow { get; set; } = new();
|
|
public List<string> ControlFlow { get; set; } = new();
|
|
}
|
|
|
|
public class ParameterInfo
|
|
{
|
|
public string Name { get; set; } = string.Empty;
|
|
public string Type { get; set; } = string.Empty;
|
|
public bool HasDefaultValue { get; set; }
|
|
public bool IsOptional { get; set; }
|
|
}
|
|
|
|
public class SpecificationRequirement
|
|
{
|
|
public string Id { get; set; } = string.Empty;
|
|
public string Description { get; set; } = string.Empty;
|
|
public string Priority { get; set; } = string.Empty;
|
|
public string Category { get; set; } = string.Empty;
|
|
}
|
|
|
|
public class BehaviorSummary
|
|
{
|
|
public string Component { get; set; } = string.Empty;
|
|
public string BehaviorType { get; set; } = string.Empty;
|
|
public string Summary { get; set; } = string.Empty;
|
|
public List<string> KeyBehaviors { get; set; } = new();
|
|
public string ComplexityLevel { get; set; } = string.Empty;
|
|
public string BusinessValue { get; set; } = string.Empty;
|
|
}
|
|
|
|
public class SpecificationAlignment
|
|
{
|
|
public string Component { get; set; } = string.Empty;
|
|
public string SpecificationRequirement { get; set; } = string.Empty;
|
|
public string ActualBehavior { get; set; } = string.Empty;
|
|
public int AlignmentLevel { get; set; }
|
|
public List<string> Discrepancies { get; set; } = new();
|
|
public List<string> Recommendations { get; set; } = new();
|
|
}
|
|
|
|
public class SemanticDrift
|
|
{
|
|
public string Component { get; set; } = string.Empty;
|
|
public string DriftType { get; set; } = string.Empty;
|
|
public string Description { get; set; } = string.Empty;
|
|
public string Severity { get; set; } = string.Empty;
|
|
public string Impact { get; set; } = string.Empty;
|
|
public string Recommendation { get; set; } = string.Empty;
|
|
public DateTime DetectedAt { get; set; }
|
|
}
|
|
|
|
public class BreakingChange
|
|
{
|
|
public string ChangeType { get; set; } = string.Empty;
|
|
public string Component { get; set; } = string.Empty;
|
|
public string Description { get; set; } = string.Empty;
|
|
public string Impact { get; set; } = string.Empty;
|
|
public string Severity { get; set; } = string.Empty;
|
|
public string MitigationStrategy { get; set; } = string.Empty;
|
|
public List<string> AffectedAPIs { get; set; } = new();
|
|
}
|
|
|
|
public class BehaviorTestSuggestion
|
|
{
|
|
public string TestType { get; set; } = string.Empty;
|
|
public string TargetComponent { get; set; } = string.Empty;
|
|
public string BehaviorToTest { get; set; } = string.Empty;
|
|
public string TestScenario { get; set; } = string.Empty;
|
|
public int Priority { get; set; }
|
|
public string Rationale { get; set; } = string.Empty;
|
|
public string Implementation { get; set; } = string.Empty;
|
|
}
|
|
|
|
public class IntentValidation
|
|
{
|
|
public string Component { get; set; } = string.Empty;
|
|
public string ComponentType { get; set; } = string.Empty;
|
|
public string ExpectedIntent { get; set; } = string.Empty;
|
|
public string ActualBehavior { get; set; } = string.Empty;
|
|
public int AlignmentScore { get; set; }
|
|
public string Finding { get; set; } = string.Empty;
|
|
public List<string> Recommendations { get; set; } = new();
|
|
}
|
|
|
|
public class BehaviorSnapshot
|
|
{
|
|
public DateTime AnalysisDate { get; set; }
|
|
public List<ClassSnapshot> Classes { get; set; } = new();
|
|
public List<MethodSnapshot> Methods { get; set; } = new();
|
|
}
|
|
|
|
public class ClassSnapshot
|
|
{
|
|
public string Name { get; set; } = string.Empty;
|
|
public string BehaviorCategory { get; set; } = string.Empty;
|
|
public List<string> Responsibilities { get; set; } = new();
|
|
public List<string> DesignPatterns { get; set; } = new();
|
|
}
|
|
|
|
public class MethodSnapshot
|
|
{
|
|
public string Name { get; set; } = string.Empty;
|
|
public string ClassName { get; set; } = string.Empty;
|
|
public string BehaviorType { get; set; } = string.Empty;
|
|
public List<string> SideEffects { get; set; } = new();
|
|
public bool HasBusinessLogic { get; set; }
|
|
}
|
|
} |