// Copyright (c) Umbraco.
// See LICENSE for more details.
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Tests.UnitTests.TestHelpers;
using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Composing;
///
/// Tests for lazy collection builder.
///
///
/// Lazy collection builder does not throw on duplicate, just uses distinct types
/// so we don't have a test for duplicates as we had with resolvers in v7.
///
[TestFixture]
public class LazyCollectionBuilderTests
{
private IServiceCollection CreateRegister() => TestHelper.GetServiceCollection();
[Test]
public void LazyCollectionBuilderHandlesTypes()
{
var container = CreateRegister();
var composition = new UmbracoBuilder(container, Mock.Of(), TestHelper.GetMockedTypeLoader());
composition.WithCollectionBuilder()
.Add()
.Add()
.Add()
.Add();
var factory = composition.CreateServiceProvider();
var values = factory.GetRequiredService();
Assert.AreEqual(3, values.Count());
Assert.IsTrue(values.Select(x => x.GetType())
.ContainsAll(new[] { typeof(TransientObject1), typeof(TransientObject2), typeof(TransientObject3) }));
var other = factory.GetRequiredService();
Assert.AreNotSame(values, other); // transient
var o1 = other.FirstOrDefault(x => x is TransientObject1);
Assert.IsFalse(values.Contains(o1)); // transient
}
[Test]
public void LazyCollectionBuilderHandlesProducers()
{
var container = CreateRegister();
var composition = new UmbracoBuilder(container, Mock.Of(), TestHelper.GetMockedTypeLoader());
composition.WithCollectionBuilder()
.Add(() => new[] { typeof(TransientObject3), typeof(TransientObject2) })
.Add(() => new[] { typeof(TransientObject3), typeof(TransientObject2) })
.Add(() => new[] { typeof(TransientObject1) });
var factory = composition.CreateServiceProvider();
var values = factory.GetRequiredService();
Assert.AreEqual(3, values.Count());
Assert.IsTrue(values.Select(x => x.GetType())
.ContainsAll(new[] { typeof(TransientObject1), typeof(TransientObject2), typeof(TransientObject3) }));
var other = factory.GetRequiredService();
Assert.AreNotSame(values, other); // transient
var o1 = other.FirstOrDefault(x => x is TransientObject1);
Assert.IsFalse(values.Contains(o1)); // transient
}
[Test]
public void LazyCollectionBuilderHandlesTypesAndProducers()
{
var container = CreateRegister();
var composition = new UmbracoBuilder(container, Mock.Of(), TestHelper.GetMockedTypeLoader());
composition.WithCollectionBuilder()
.Add()
.Add()
.Add()
.Add(() => new[] { typeof(TransientObject1) });
var factory = composition.CreateServiceProvider();
var values = factory.GetRequiredService();
Assert.AreEqual(3, values.Count());
Assert.IsTrue(values.Select(x => x.GetType())
.ContainsAll(new[] { typeof(TransientObject1), typeof(TransientObject2), typeof(TransientObject3) }));
var other = factory.GetRequiredService();
Assert.AreNotSame(values, other); // transient
var o1 = other.FirstOrDefault(x => x is TransientObject1);
Assert.IsFalse(values.Contains(o1)); // transient
}
[Test]
public void LazyCollectionBuilderThrowsOnIllegalTypes()
{
var container = CreateRegister();
var composition = new UmbracoBuilder(container, Mock.Of(), TestHelper.GetMockedTypeLoader());
composition.WithCollectionBuilder()
.Add()
// illegal, does not implement the interface!
////.Add()
// legal so far...
.Add(() => new[] { typeof(TransientObject4) });
Assert.Throws(() =>
{
// but throws here when trying to register the types, right before creating the factory
var factory = composition.CreateServiceProvider();
});
}
[Test]
public void LazyCollectionBuilderCanExcludeTypes()
{
var container = CreateRegister();
var composition = new UmbracoBuilder(container, Mock.Of(), TestHelper.GetMockedTypeLoader());
composition.WithCollectionBuilder()
.Add()
.Add(() => new[] { typeof(TransientObject3), typeof(TransientObject2), typeof(TransientObject1) })
.Exclude();
var factory = composition.CreateServiceProvider();
var values = factory.GetRequiredService();
Assert.AreEqual(2, values.Count());
Assert.IsFalse(values.Select(x => x.GetType())
.Contains(typeof(TransientObject3)));
Assert.IsTrue(values.Select(x => x.GetType())
.ContainsAll(new[] { typeof(TransientObject1), typeof(TransientObject2) }));
var other = factory.GetRequiredService();
Assert.AreNotSame(values, other); // transient
var o1 = other.FirstOrDefault(x => x is TransientObject1);
Assert.IsFalse(values.Contains(o1)); // transient
}
private interface ITestInterface
{
}
private class TransientObject1 : ITestInterface
{
}
private class TransientObject2 : ITestInterface
{
}
private class TransientObject3 : ITestInterface
{
}
private class TransientObject4
{
}
// ReSharper disable once ClassNeverInstantiated.Local
private class
TestCollectionBuilder : LazyCollectionBuilderBase
{
protected override TestCollectionBuilder This => this;
protected override ServiceLifetime CollectionLifetime => ServiceLifetime.Transient; // transient
}
// ReSharper disable once ClassNeverInstantiated.Local
private class TestCollection : BuilderCollectionBase
{
public TestCollection(Func> items)
: base(items)
{
}
}
}