Skip to content
Open
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
### Version: 1.1.0
#### Date: March-24-2026
- Added `GetVariantAliases` and `GetDataCsvariantsAttribute` for variant alias extraction and `data-csvariants` serialization; Invalid arguments throw `ArgumentException`.


### Version: 1.0.7
#### Date: January-12-2026
- Improved error messages
Expand Down
3 changes: 3 additions & 0 deletions Contentstack.Utils.Tests/Contentstack.Utils.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,7 @@
<ItemGroup>
<None Remove="contentstack.csharp" />
</ItemGroup>
<ItemGroup>
<Content Include="Resources\**\*.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
</Project>
71 changes: 71 additions & 0 deletions Contentstack.Utils.Tests/Resources/variantsEntries.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
{
"entries": [
{
"uid": "entry_uid_1",
"_metadata": {},
"locale": "en-us",
"_version": 1,
"title": "Sample Movie",
"publish_details": {
"time": "2025-12-11T07:56:17.574Z",
"user": "test_user",
"environment": "test_env",
"locale": "en-us",
"variants": {
"cs_variant_0_0": {
"alias": "cs_personalize_0_0",
"environment": "test_env",
"time": "2025-12-11T07:56:17.574Z",
"locale": "en-us",
"user": "test_user",
"version": 1
},
"cs_variant_0_3": {
"alias": "cs_personalize_0_3",
"environment": "test_env",
"time": "2025-12-11T07:56:17.582Z",
"locale": "en-us",
"user": "test_user",
"version": 1
}
}
}
},
{
"uid": "entry_uid_2",
"_metadata": {},
"locale": "en-us",
"_version": 2,
"title": "Another Movie",
"publish_details": {
"time": "2025-12-11T07:10:19.964Z",
"user": "test_user",
"environment": "test_env",
"locale": "en-us",
"variants": {
"cs_variant_0_0": {
"alias": "cs_personalize_0_0",
"environment": "test_env",
"time": "2025-12-11T07:10:19.964Z",
"locale": "en-us",
"user": "test_user",
"version": 2
}
}
}
},
{
"uid": "entry_uid_3",
"_metadata": {},
"locale": "en-us",
"_version": 1,
"title": "Movie No Variants",
"publish_details": {
"time": "2025-11-20T10:00:00.000Z",
"user": "test_user",
"environment": "test_env",
"locale": "en-us"
}
}
]
}
39 changes: 39 additions & 0 deletions Contentstack.Utils.Tests/Resources/variantsSingleEntry.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"entry": {
"uid": "entry_uid_single",
"_metadata": {},
"locale": "en-us",
"_version": 1,
"ACL": {},
"_in_progress": false,
"title": "Sample Movie",
"created_at": "2025-11-20T10:00:00.000Z",
"updated_at": "2025-12-11T07:56:17.574Z",
"created_by": "test_user",
"updated_by": "test_user",
"publish_details": {
"time": "2025-12-11T07:56:17.574Z",
"user": "test_user",
"environment": "test_env",
"locale": "en-us",
"variants": {
"cs_variant_0_0": {
"alias": "cs_personalize_0_0",
"environment": "test_env",
"time": "2025-12-11T07:56:17.574Z",
"locale": "en-us",
"user": "test_user",
"version": 1
},
"cs_variant_0_3": {
"alias": "cs_personalize_0_3",
"environment": "test_env",
"time": "2025-12-11T07:56:17.582Z",
"locale": "en-us",
"user": "test_user",
"version": 1
}
}
}
}
}
257 changes: 257 additions & 0 deletions Contentstack.Utils.Tests/VariantAliasesTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
using System;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json.Linq;
using Xunit;

namespace Contentstack.Utils.Tests
{
public class VariantAliasesTest
{
private static JObject ReadJsonRoot(string fileName)
{
var path = Path.Combine(AppContext.BaseDirectory, "Resources", fileName);
return JObject.Parse(File.ReadAllText(path));
}

private static HashSet<string> JsonArrayToStringSet(JArray arr)
{
var set = new HashSet<string>();
foreach (var t in arr)
{
set.Add(t.ToString());
}
return set;
}

[Fact]
public void GetVariantAliases_SingleEntry_ReturnsAliases()
{
JObject full = ReadJsonRoot("variantsSingleEntry.json");
JObject entry = (JObject)full["entry"];
const string contentTypeUid = "movie";

JObject result = Utils.GetVariantAliases(entry, contentTypeUid);

Assert.True(result["entry_uid"] != null && !string.IsNullOrEmpty(result["entry_uid"].ToString()));
Assert.Equal(contentTypeUid, result["contenttype_uid"].ToString());
JArray variants = (JArray)result["variants"];
Assert.NotNull(variants);
var aliasSet = JsonArrayToStringSet(variants);
Assert.Equal(
new HashSet<string> { "cs_personalize_0_0", "cs_personalize_0_3" },
aliasSet);
}

[Fact]
public void GetDataCsvariantsAttribute_SingleEntry_ReturnsJsonArrayString()
{
JObject full = ReadJsonRoot("variantsSingleEntry.json");
JObject entry = (JObject)full["entry"];
const string contentTypeUid = "movie";

JObject result = Utils.GetDataCsvariantsAttribute(entry, contentTypeUid);

Assert.True(result["data-csvariants"] != null);
string dataCsvariantsStr = result["data-csvariants"].ToString();
JArray arr = JArray.Parse(dataCsvariantsStr);
Assert.Single(arr);
JObject first = (JObject)arr[0];
Assert.True(first["entry_uid"] != null && !string.IsNullOrEmpty(first["entry_uid"].ToString()));
Assert.Equal(contentTypeUid, first["contenttype_uid"].ToString());
var aliasSet = JsonArrayToStringSet((JArray)first["variants"]);
Assert.Equal(
new HashSet<string> { "cs_personalize_0_0", "cs_personalize_0_3" },
aliasSet);
}

[Fact]
public void GetVariantAliases_MultipleEntries_ReturnsOneResultPerEntryWithUid()
{
JObject full = ReadJsonRoot("variantsEntries.json");
JArray entries = (JArray)full["entries"];
const string contentTypeUid = "movie";

JArray result = Utils.GetVariantAliases(entries, contentTypeUid);

Assert.NotNull(result);
Assert.Equal(3, result.Count);

JObject first = (JObject)result[0];
Assert.True(first["entry_uid"] != null && !string.IsNullOrEmpty(first["entry_uid"].ToString()));
Assert.Equal(contentTypeUid, first["contenttype_uid"].ToString());
var firstSet = JsonArrayToStringSet((JArray)first["variants"]);
Assert.Equal(
new HashSet<string> { "cs_personalize_0_0", "cs_personalize_0_3" },
firstSet);

JObject second = (JObject)result[1];
Assert.True(second["entry_uid"] != null && !string.IsNullOrEmpty(second["entry_uid"].ToString()));
Assert.Single((JArray)second["variants"]);
Assert.Equal("cs_personalize_0_0", ((JArray)second["variants"])[0].ToString());

JObject third = (JObject)result[2];
Assert.True(third["entry_uid"] != null && !string.IsNullOrEmpty(third["entry_uid"].ToString()));
Assert.Empty((JArray)third["variants"]);
}

[Fact]
public void GetDataCsvariantsAttribute_MultipleEntries_ReturnsJsonArrayString()
{
JObject full = ReadJsonRoot("variantsEntries.json");
JArray entries = (JArray)full["entries"];
const string contentTypeUid = "movie";

JObject result = Utils.GetDataCsvariantsAttribute(entries, contentTypeUid);

Assert.True(result["data-csvariants"] != null);
string dataCsvariantsStr = result["data-csvariants"].ToString();
JArray arr = JArray.Parse(dataCsvariantsStr);
Assert.Equal(3, arr.Count);
Assert.True(((JObject)arr[0])["entry_uid"] != null && !string.IsNullOrEmpty(((JObject)arr[0])["entry_uid"].ToString()));
Assert.Equal(2, ((JArray)((JObject)arr[0])["variants"]).Count);
Assert.True(((JObject)arr[1])["entry_uid"] != null && !string.IsNullOrEmpty(((JObject)arr[1])["entry_uid"].ToString()));
Assert.Single((JArray)((JObject)arr[1])["variants"]);
Assert.True(((JObject)arr[2])["entry_uid"] != null && !string.IsNullOrEmpty(((JObject)arr[2])["entry_uid"].ToString()));
Assert.Empty((JArray)((JObject)arr[2])["variants"]);
}

[Fact]
public void GetVariantAliases_ThrowsWhenEntryNull()
{
Assert.Throws<ArgumentException>(() => Utils.GetVariantAliases((JObject)null, "landing_page"));
}

[Fact]
public void GetVariantAliases_ThrowsWhenContentTypeUidNull()
{
JObject full = ReadJsonRoot("variantsSingleEntry.json");
JObject entry = (JObject)full["entry"];
Assert.Throws<ArgumentException>(() => Utils.GetVariantAliases(entry, null));
}

[Fact]
public void GetVariantAliases_ThrowsWhenContentTypeUidEmpty()
{
JObject full = ReadJsonRoot("variantsSingleEntry.json");
JObject entry = (JObject)full["entry"];
Assert.Throws<ArgumentException>(() => Utils.GetVariantAliases(entry, ""));
}

[Fact]
public void GetDataCsvariantsAttribute_WhenEntryNull_ReturnsEmptyArrayString()
{
JObject result = Utils.GetDataCsvariantsAttribute((JObject)null, "landing_page");
Assert.True(result["data-csvariants"] != null);
Assert.Equal("[]", result["data-csvariants"].ToString());
}

[Fact]
public void GetVariantAliases_ThrowsWhenUidMissing()
{
var entry = new JObject { ["title"] = "no-uid" };
Assert.Throws<ArgumentException>(() => Utils.GetVariantAliases(entry, "movie"));
}

[Fact]
public void GetVariantAliases_ThrowsWhenUidNull()
{
var entry = new JObject { ["uid"] = JValue.CreateNull() };
Assert.Throws<ArgumentException>(() => Utils.GetVariantAliases(entry, "movie"));
}

[Fact]
public void GetVariantAliases_Batch_ThrowsWhenContentTypeUidNull()
{
var entries = new JArray { new JObject { ["uid"] = "a" } };
Assert.Throws<ArgumentException>(() => Utils.GetVariantAliases(entries, null));
}

[Fact]
public void GetVariantAliases_Batch_ThrowsWhenContentTypeUidEmpty()
{
var entries = new JArray { new JObject { ["uid"] = "a" } };
Assert.Throws<ArgumentException>(() => Utils.GetVariantAliases(entries, ""));
}

[Fact]
public void GetDataCsvariantsAttribute_WhenEntriesArrayNull_ReturnsEmptyArrayString()
{
JObject result = Utils.GetDataCsvariantsAttribute((JArray)null, "movie");
Assert.Equal("[]", result["data-csvariants"].ToString());
}

[Fact]
public void GetDataCsvariantsAttribute_Batch_ThrowsWhenContentTypeUidNull()
{
var entries = new JArray { new JObject { ["uid"] = "a" } };
Assert.Throws<ArgumentException>(() => Utils.GetDataCsvariantsAttribute(entries, null));
}

[Fact]
public void GetDataCsvariantsAttribute_Batch_ThrowsWhenContentTypeUidEmpty()
{
var entries = new JArray { new JObject { ["uid"] = "a" } };
Assert.Throws<ArgumentException>(() => Utils.GetDataCsvariantsAttribute(entries, ""));
}

[Fact]
public void GetVariantAliases_ReturnsEmptyVariantsWhenPublishDetailsMissing()
{
var entry = new JObject { ["uid"] = "blt_no_pd" };
JObject result = Utils.GetVariantAliases(entry, "movie");
Assert.Equal("blt_no_pd", result["entry_uid"].ToString());
Assert.Equal("movie", result["contenttype_uid"].ToString());
Assert.Empty((JArray)result["variants"]);
}

[Fact]
public void GetVariantAliases_ReturnsEmptyVariantsWhenVariantsObjectEmpty()
{
var entry = new JObject
{
["uid"] = "blt_empty_v",
["publish_details"] = new JObject
{
["variants"] = new JObject()
}
};
JObject result = Utils.GetVariantAliases(entry, "movie");
Assert.Empty((JArray)result["variants"]);
}

[Fact]
public void GetVariantAliases_ReturnsEmptyVariantsWhenVariantsKeyMissing()
{
var entry = new JObject
{
["uid"] = "blt_no_variants_key",
["publish_details"] = new JObject { ["time"] = "2025-01-01T00:00:00.000Z" }
};
JObject result = Utils.GetVariantAliases(entry, "movie");
Assert.Empty((JArray)result["variants"]);
}

[Fact]
public void GetVariantAliases_SkipsVariantWhenAliasMissingOrEmpty()
{
var entry = new JObject
{
["uid"] = "blt_skip",
["publish_details"] = new JObject
{
["variants"] = new JObject
{
["v1"] = new JObject { ["alias"] = "keep_me" },
["v2"] = new JObject(),
["v3"] = new JObject { ["alias"] = "" }
}
}
};
JObject result = Utils.GetVariantAliases(entry, "page");
var variants = (JArray)result["variants"];
Assert.Single(variants);
Assert.Equal("keep_me", variants[0].ToString());
}
}
}
Loading
Loading