Skip to content

Commit

Permalink
Shows an error when it cannot resolve a composition root.
Browse files Browse the repository at this point in the history
  • Loading branch information
Nikolay Pyanikov committed Aug 6, 2023
1 parent 3aade8f commit 09f95c9
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 78 deletions.
2 changes: 1 addition & 1 deletion src/Pure.DI.Core/Core/Code/ClassDiagramBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ private static string FormatInjection(Injection injection, FormatOptions options
$"{FormatTag(injection.Tag)}{FormatSymbol(injection.Type, options)}";

private static string FormatDependency(Dependency dependency, FormatOptions options) =>
$"{(dependency.Injection.Tag == default ? "" : FormatTag(dependency.Injection.Tag) + " ")}{FormatSymbol(dependency.TargetSymbol, options)}";
$"{(dependency.Injection.Tag == default ? "" : FormatTag(dependency.Injection.Tag) + " ")}{FormatSymbol(dependency.Injection.Type, options)}";

private static string FormatTag(object? tag) =>
tag != default ? $"{tag.ValueToString("").Replace("\"", "\\\"")} " : "";
Expand Down
38 changes: 0 additions & 38 deletions src/Pure.DI.Core/Core/DependenciesToSymbolsWalker.cs

This file was deleted.

37 changes: 5 additions & 32 deletions src/Pure.DI.Core/Core/DependencyGraphBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -194,48 +194,21 @@ bool TryCreateOnCannotResolve(MdSetup mdSetup, DependencyNode ownerNode, Injecti
}

var entries = new List<GraphEntry<DependencyNode, Dependency>>(processed.Count);
var unresolvedSource = new DependencyNode(0);
foreach (var node in processed)
foreach (var node in processed.Concat(notProcessed))
{
var edges = new List<Dependency>(node.Injections.Length);
var symbolsWalker = new DependenciesToSymbolsWalker();
symbolsWalker.VisitDependencyNode(node.Node);
var symbols = symbolsWalker.ToArray();
IEnumerable<(Injection injection, ISymbol? symbol)> pairs = symbols.Length == node.Injections.Length
? node.Injections.Zip(symbols, (injection, symbol) => (injection, (ISymbol?)symbol))
: node.Injections.Select(injection => (injection, default(ISymbol)));

foreach (var (injection, symbol) in pairs)
foreach (var injection in node.Injections)
{
var dependency = map.TryGetValue(injection, out var sourceNode)
? new Dependency(true, sourceNode, injection, node.Node, symbol)
: new Dependency(false, unresolvedSource, injection, node.Node, symbol);
? new Dependency(true, sourceNode, injection, node.Node)
: new Dependency(false, new DependencyNode(0), injection, node.Node);

edges.Add(dependency);
}

entries.Add(new GraphEntry<DependencyNode, Dependency>(node.Node, edges.ToImmutableArray()));
}

if (notProcessed.Any())
{
foreach (var node in notProcessed)
{
var edges = new List<Dependency>(node.Injections.Length);
var symbols = new DependenciesToSymbolsWalker();
symbols.VisitDependencyNode(node.Node);
foreach (var (injection, symbol) in node.Injections.Zip(symbols, (injection, symbol) => (injection, symbol)))
{
var dependency = map.TryGetValue(injection, out var sourceNode)
? new Dependency(true, sourceNode, injection, node.Node, symbol)
: new Dependency(false, unresolvedSource, injection, node.Node, symbol);
edges.Add(dependency);
}

entries.Add(new GraphEntry<DependencyNode, Dependency>(node.Node, edges.ToImmutableArray()));
}
}


dependencyGraph = new DependencyGraph(
isValid,
setup,
Expand Down
6 changes: 3 additions & 3 deletions src/Pure.DI.Core/Core/DependencyGraphValidator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ public void Validate(in DependencyGraph dependencyGraph)
foreach (var dependency in graph.Edges.Where(i => !i.IsResolved))
{
_cancellationToken.ThrowIfCancellationRequested();
var errorMessage = $"Cannot resolve dependency \"{dependency.TargetSymbol?.ToString() ?? dependency.Injection.ToString()}\" in {dependency.Target.Type}.";
var errorMessage = $"Unable to resolve \"{dependency.Injection}\" in {dependency.Target}.";
var locationsWalker = new DependencyGraphLocationsWalker(dependency.Injection);
locationsWalker.VisitDependencyNode(dependency.Target);
foreach (var location in locationsWalker.Locations)
{
_logger.CompileError(errorMessage, location, LogId.ErrorUnresolvedDependency);
_logger.CompileError(errorMessage, location, LogId.ErrorUnableToResolve);
isErrorReported = true;
}
}
Expand Down Expand Up @@ -103,7 +103,7 @@ public void Validate(in DependencyGraph dependencyGraph)

if (!isErrorReported)
{
_logger.CompileError("Cannot build a dependency graph.", dependencyGraph.Source.Source.GetLocation(), LogId.ErrorUnresolvedDependency);
_logger.CompileError("Cannot build a dependency graph.", dependencyGraph.Source.Source.GetLocation(), LogId.ErrorUnableToResolve);
}

throw HandledException.Shared;
Expand Down
2 changes: 1 addition & 1 deletion src/Pure.DI.Core/Core/LogId.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ namespace Pure.DI.Core;
internal static class LogId
{
// Errors
public const string ErrorUnresolvedDependency = "DIE000";
public const string ErrorUnableToResolve = "DIE000";
public const string ErrorCyclicDependency = "DIE001";
public const string ErrorCannotFindSetup = "DIE002";
public const string ErrorInvalidMetadata = "DIE003";
Expand Down
3 changes: 1 addition & 2 deletions src/Pure.DI.Core/Core/Models/Dependency.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ internal readonly record struct Dependency(
bool IsResolved,
DependencyNode Source,
in Injection Injection,
DependencyNode Target,
ISymbol? TargetSymbol)
DependencyNode Target)
: IEdge<DependencyNode>
{
public override string ToString() => $"[{Target}]<--[{Injection.ToString()}]--[{Source}]";
Expand Down
2 changes: 1 addition & 1 deletion tests/Pure.DI.IntegrationTests/GraphTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ public class Program { public static void Main() { } }
-[Dependency(int id<--int), string abc<--string))]<--[string]--[unresolved]
""");

var errors = result.Logs.Where(i => i.Id == LogId.ErrorUnresolvedDependency).ToImmutableArray();
var errors = result.Logs.Where(i => i.Id == LogId.ErrorUnableToResolve).ToImmutableArray();
errors.Length.ShouldBe(1);
}

Expand Down
49 changes: 49 additions & 0 deletions tests/Pure.DI.IntegrationTests/SetupTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,55 @@ public static void Main()
result.Errors.Count.ShouldBe(2);
}

[Fact]
public async Task ShouldShowErrorWhenCannotResolveRoot()
{
// Given

// When
var result = await """
using System;
using Pure.DI;
namespace Sample
{
interface IService
{
}
class Service: IService
{
}
static class Setup
{
private static void SetupComposition()
{
DI.Setup("Composition")
.Bind<IService>(1).To<Service>()
.Root<IService>("MyRoot1");
}
}
public class Program
{
public static void Main()
{
var composition = new Composition();
}
}
}
""".RunAsync();

// Then
result.Success.ShouldBeFalse(result);
result.Errors
.Count(i =>
i.Id == LogId.ErrorUnableToResolve
&& i.Lines.FirstOrDefault() == "Unable to resolve \"Sample.IService\" in Sample.IService() MyRoot1.")
.ShouldBe(1);
}

[Fact]
public async Task ShouldOverrideBinding()
{
Expand Down

0 comments on commit 09f95c9

Please sign in to comment.