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
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using FluentAssertions;
using Kontent.Ai.Management.Configuration;
using System;
using System.Net.Http;
using Xunit;

namespace Kontent.Ai.Management.Tests.ManagementClientTests;

public class ConstructorTests
{
private static ManagementClient CreateClient(ManagementOptions options, bool useHttpClient)
=> useHttpClient
? new ManagementClient(options, new HttpClient())
: new ManagementClient(options);

[Theory]
[InlineData(false)]
[InlineData(true)]
public void Ctor_ValidOptions_DoesNotThrow(bool useHttpClient)
{
var options = new ManagementOptions
{
EnvironmentId = Guid.NewGuid().ToString(),
ApiKey = "valid-key"
};

Action act = () => CreateClient(options, useHttpClient);
act.Should().NotThrow();
}

[Theory]
[InlineData(false)]
[InlineData(true)]
public void Ctor_NullOptions_ThrowsArgumentNull(bool useHttpClient)
{
Action act = () => CreateClient(null!, useHttpClient);

act.Should().Throw<ArgumentNullException>();
}

[Theory]
[InlineData("", "key", "environment identifier is not specified")]
[InlineData("no-guid", "key", "not a valid environment identifier")]
[InlineData("4ee3d5cc-2e5b-4c81-9f4c-6a8f7b5d3c1e", "", "API key is not specified")]
public void Ctor_InvalidOptions_ThrowsArgument(
string envId,
string apiKey,
string messagePart)
{
var options = new ManagementOptions
{
EnvironmentId = envId,
ApiKey = apiKey
};

Action act = () => CreateClient(options, false);

act.Should()
.Throw<ArgumentException>()
.WithMessage($"*{messagePart}*");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
using FluentAssertions;
using Kontent.Ai.Management.Models.LanguageVariants.Elements;
using Kontent.Ai.Management.Models.Shared;
using Kontent.Ai.Management.Models.Types.Elements;
using System;
using System.Collections.Generic;
using System.Linq;
using Xunit;

namespace Kontent.Ai.Management.Tests.Modules.ModelBuilders;

public class BaseElementRoundTripTests
{
public static IEnumerable<object[]> ReferenceElementTestCases()
{
yield return new object[] {
new TaxonomyElement {
Element = Reference.ByCodename("tax"),
Value = [Reference.ByCodename("t1"), Reference.ByCodename("t2")]
},
ElementMetadataType.Taxonomy,
new Action<BaseElement>(converted => {
var e = (TaxonomyElement)converted;
e.Element.Codename.Should().Be("tax");
e.Value.Should().HaveCount(2);
e.Value.First().Codename.Should().Be("t1");
e.Value.Last().Codename.Should().Be("t2");
})
};

yield return new object[] {
new LinkedItemsElement {
Element = Reference.ByCodename("link"),
Value = [Reference.ByCodename("i1"), Reference.ByExternalId("ext2")]
},
ElementMetadataType.LinkedItems,
new Action<BaseElement>(converted => {
var e = (LinkedItemsElement)converted;
e.Element.Codename.Should().Be("link");
e.Value.Should().HaveCount(2);
e.Value.First().Codename.Should().Be("i1");
e.Value.Last().ExternalId.Should().Be("ext2");
})
};

yield return new object[] {
new MultipleChoiceElement {
Element = Reference.ByCodename("mc"),
Value = [Reference.ByCodename("o1"), Reference.ByCodename("o2")]
},
ElementMetadataType.MultipleChoice,
new Action<BaseElement>(converted => {
var e = (MultipleChoiceElement)converted;
e.Element.Codename.Should().Be("mc");
e.Value.Should().HaveCount(2);
e.Value.First().Codename.Should().Be("o1");
e.Value.Last().Codename.Should().Be("o2");
})
};

yield return new object[] {
new SubpagesElement {
Element = Reference.ByCodename("sp"),
Value = [Reference.ByCodename("p1"), Reference.ByCodename("p2")]
},
ElementMetadataType.Subpages,
new Action<BaseElement>(converted => {
var e = (SubpagesElement)converted;
e.Element.Codename.Should().Be("sp");
e.Value.Should().HaveCount(2);
e.Value.First().Codename.Should().Be("p1");
e.Value.Last().Codename.Should().Be("p2");
})
};
}

[Theory]
[MemberData(nameof(ReferenceElementTestCases))]
public void ReferenceElements_RoundTrip_PreservesValues(BaseElement original, ElementMetadataType type, Action<BaseElement> assertConverted)
{
// Act
var dynamic = original.ToDynamic();
var converted = BaseElement.FromDynamic(dynamic, type);

// Assert
assertConverted(converted);
}

public static IEnumerable<object[]> AssetElementTestCases()
{
yield return new object[] {
new AssetElement {
Element = Reference.ByCodename("asset"),
Value = [
new AssetWithRenditionsReference(Reference.ByCodename("a1"), [Reference.ByCodename("r1")]),
new AssetWithRenditionsReference(Reference.ByCodename("a2"))
]
},
new Action<AssetElement>(converted => {
var assets = converted.Value.ToArray();
converted.Element.Codename.Should().Be("asset");
assets[0].Codename.Should().Be("a1");
assets[0].Renditions.Should().HaveCount(1);
assets[0].Renditions.First().Codename.Should().Be("r1");
assets[1].Codename.Should().Be("a2");
assets[1].Renditions.Should().BeEmpty();
})
};

yield return new object[] {
new AssetElement {
Element = Reference.ByCodename("asset"),
Value = [
new AssetWithRenditionsReference(Reference.ById(Guid.NewGuid()), [Reference.ByCodename("rn")]),
new AssetWithRenditionsReference(Reference.ByExternalId("ext_a"), [Reference.ByExternalId("ext_r")])
]
},
new Action<AssetElement>(converted => {
var assets = converted.Value.ToArray();
assets[0].Id.Should().NotBeNull();
assets[0].Renditions.First().Codename.Should().Be("rn");
assets[1].ExternalId.Should().Be("ext_a");
assets[1].Renditions.First().ExternalId.Should().Be("ext_r");
})
};

yield return new object[] {
new AssetElement {
Element = Reference.ByCodename("asset"),
Value = null
},
new Action<AssetElement>(converted => {
converted.Value.Should().BeNull();
})
};
}

[Theory]
[MemberData(nameof(AssetElementTestCases))]
public void AssetElement_RoundTrip_PreservesValues(AssetElement original, Action<AssetElement> assertConverted)
{
// Act
var dynamic = original.ToDynamic();
var converted = (AssetElement)BaseElement.FromDynamic(dynamic, ElementMetadataType.Asset);

// Assert
assertConverted(converted);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,19 +85,19 @@ public void GetLanguageVariantUpsertModel_ReturnsExpected()

var relatedArticlesValue = dynamicElements.SingleOrDefault(elementObject =>
elementObject.element.id == type.GetProperty(nameof(model.RelatedArticles))?.GetKontentElementId()
).value as IEnumerable<Reference>;
).value as IEnumerable<dynamic>;

var teaserImageValue = dynamicElements.SingleOrDefault(elementObject =>
elementObject.element.id == type.GetProperty(nameof(model.TeaserImage))?.GetKontentElementId()
).value as IEnumerable<AssetWithRenditionsReference>;
).value as IEnumerable<dynamic>;

var personaValue = dynamicElements.SingleOrDefault(elementObject =>
elementObject.element.id == type.GetProperty(nameof(model.Personas))?.GetKontentElementId()
).value as IEnumerable<Reference>;
).value as IEnumerable<dynamic>;

var optionsValue = dynamicElements.SingleOrDefault(elementObject =>
elementObject.element.id == type.GetProperty(nameof(model.Options))?.GetKontentElementId()
).value as IEnumerable<Reference>;
).value as IEnumerable<dynamic>;

Assert.Equal(model.Title.Value, titleValue);
Assert.Equal(model.Rating.Value, ratingValue);
Expand All @@ -110,10 +110,10 @@ public void GetLanguageVariantUpsertModel_ReturnsExpected()
Assert.Equal(model.BodyCopy.Value, bodyCopyElement.value);
Assert.Single(bodyCopyElement.components as IEnumerable<ComponentModel>);
AssertIdentifiers(model.BodyCopy.Components.Select(x => x.Id), (bodyCopyElement.components as IEnumerable<ComponentModel>)?.Select(x => x.Id));
AssertIdentifiers(model.RelatedArticles.Value.Select(x => x.Id.Value), relatedArticlesValue.Select(x => x.Id.Value));
AssertIdentifiers(model.TeaserImage.Value.Select(x => x.Id.Value), teaserImageValue.Select(x => x.Id.Value));
AssertIdentifiers(model.Personas.Value.Select(x => x.Id.Value), personaValue.Select(x => x.Id.Value));
AssertIdentifiers(model.Options.Value.Select(x => x.Id.Value), optionsValue.Select(x => x.Id.Value));
AssertIdentifiers(model.RelatedArticles.Value.Select(x => x.Id.Value), relatedArticlesValue?.Select(r => Reference.FromDynamic(r).Id ?? Guid.Empty).Cast<Guid>() ?? Enumerable.Empty<Guid>());
AssertIdentifiers(model.TeaserImage.Value.Select(x => x.Id.Value), teaserImageValue?.Select(a => AssetWithRenditionsReference.FromDynamic(a).Id ?? Guid.Empty).Cast<Guid>() ?? Enumerable.Empty<Guid>());
AssertIdentifiers(model.Personas.Value.Select(x => x.Id.Value), personaValue?.Select(p => Reference.FromDynamic(p).Id ?? Guid.Empty).Cast<Guid>() ?? Enumerable.Empty<Guid>());
AssertIdentifiers(model.Options.Value.Select(x => x.Id.Value), optionsValue?.Select(o => Reference.FromDynamic(o).Id ?? Guid.Empty).Cast<Guid>() ?? Enumerable.Empty<Guid>());
}

private static ComplexTestModel GetTestModel()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,5 +116,23 @@ public void ToDynamic_NoIdentifier_ThrowException()
.WithMessage("Element reference does not contain any identifier.");
}

[Fact]
public void AssetWithRenditionsReference_FromDynamic_WithInvalidData_ThrowsDataMisalignedException()
{
Action action = () => AssetWithRenditionsReference.FromDynamic(new { invalidProperty = "invalid" });

action.Should()
.Throw<DataMisalignedException>()
.WithMessage("Object could not be converted to the strongly-typed AssetWithRenditionsReference. Please check if it has expected properties with expected type");
}

[Fact]
public void AssetWithRenditionsReference_FromDynamic_WithNullData_ThrowsDataMisalignedException()
{
Action action = () => AssetWithRenditionsReference.FromDynamic(null);

action.Should()
.Throw<DataMisalignedException>()
.WithMessage("Object could not be converted to the strongly-typed AssetWithRenditionsReference. Please check if it has expected properties with expected type");
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Kontent.Ai.Management.Models.Shared;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;

namespace Kontent.Ai.Management.Models.LanguageVariants.Elements;

Expand All @@ -20,6 +21,6 @@ public class AssetElement : BaseElement
/// </summary>
public override dynamic ToDynamic() => new {
element = Element.ToDynamic(),
value = Value,
value = Value?.Select(v => v.ToDynamic()),
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,7 @@ public static BaseElement FromDynamic(dynamic source, Type type)
return new AssetElement
{
Element = Reference.FromDynamic(source.element),
Value = (source.value as IEnumerable<dynamic>)?
.Select(assetWithRenditionsReferences =>
new AssetWithRenditionsReference(
Reference.ById(Guid.Parse(assetWithRenditionsReferences.id)),
(assetWithRenditionsReferences.renditions as IEnumerable<dynamic>)?.Select<dynamic, Reference>(renditionIdentifier => Reference.ById(Guid.Parse(renditionIdentifier.id))))),
Value = (source.value as IEnumerable<dynamic>)?.Select(AssetWithRenditionsReference.FromDynamic)
};
}
else if (type == typeof(DateTimeElement))
Expand All @@ -108,23 +104,23 @@ public static BaseElement FromDynamic(dynamic source, Type type)
return new LinkedItemsElement
{
Element = Reference.FromDynamic(source.element),
Value = (source.value as IEnumerable<dynamic>)?.Select<dynamic, Reference>(identifier => Reference.ById(Guid.Parse(identifier.id)))
Value = (source.value as IEnumerable<dynamic>)?.Select(Reference.FromDynamic)
};
}
else if (type == typeof(MultipleChoiceElement))
{
return new MultipleChoiceElement
{
Element = Reference.FromDynamic(source.element),
Value = (source.value as IEnumerable<dynamic>)?.Select<dynamic, Reference>(identifier => Reference.ById(Guid.Parse(identifier.id)))
Value = (source.value as IEnumerable<dynamic>)?.Select(Reference.FromDynamic)
};
}
else if (type == typeof(TaxonomyElement))
{
return new TaxonomyElement
{
Element = Reference.FromDynamic(source.element),
Value = (source.value as IEnumerable<dynamic>)?.Select<dynamic, Reference>(identifier => Reference.ById(Guid.Parse(identifier.id)))
Value = (source.value as IEnumerable<dynamic>)?.Select(Reference.FromDynamic)
};
}
else if (type == typeof(UrlSlugElement))
Expand All @@ -150,7 +146,7 @@ public static BaseElement FromDynamic(dynamic source, Type type)
return new SubpagesElement
{
Element = Reference.FromDynamic(source.element),
Value = (source.value as IEnumerable<dynamic>)?.Select<dynamic, Reference>(identifier => Reference.ById(Guid.Parse(identifier.id)))
Value = (source.value as IEnumerable<dynamic>)?.Select(Reference.FromDynamic)
};
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Kontent.Ai.Management.Models.Shared;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;

namespace Kontent.Ai.Management.Models.LanguageVariants.Elements;

Expand All @@ -20,6 +21,6 @@ public class LinkedItemsElement : BaseElement
/// </summary>
public override dynamic ToDynamic() => new {
element = Element.ToDynamic(),
value = Value,
value = Value?.Select(v => v.ToDynamic()),
};
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Kontent.Ai.Management.Models.Shared;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;

namespace Kontent.Ai.Management.Models.LanguageVariants.Elements;

Expand All @@ -20,6 +21,6 @@ public class MultipleChoiceElement : BaseElement
/// </summary>
public override dynamic ToDynamic() => new {
element = Element.ToDynamic(),
value = Value,
value = Value?.Select(v => v.ToDynamic()),
};
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Kontent.Ai.Management.Models.Shared;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;

namespace Kontent.Ai.Management.Models.LanguageVariants.Elements;

Expand All @@ -20,6 +21,6 @@ public class SubpagesElement : BaseElement
/// </summary>
public override dynamic ToDynamic() => new {
element = Element.ToDynamic(),
value = Value,
value = Value?.Select(v => v.ToDynamic()),
};
}
Loading
Loading