From 8f7622a95dca6700a294dce39c5423b3c13c5650 Mon Sep 17 00:00:00 2001 From: reeshika-h Date: Tue, 17 Mar 2026 19:26:41 +0530 Subject: [PATCH 1/3] Feat: Variants Utility --- .gitignore | 2 + pom.xml | 14 + .../java/com/contentstack/utils/Utils.java | 272 +++++++++++++----- .../com/contentstack/utils/AssetLinkTest.java | 1 - .../com/contentstack/utils/ReadResource.java | 2 - .../java/com/contentstack/utils/TestRte.java | 4 - .../com/contentstack/utils/UtilTests.java | 128 +++++++++ src/test/resources/variant_entries.json | 71 +++++ src/test/resources/variant_entry_single.json | 39 +++ 9 files changed, 458 insertions(+), 75 deletions(-) create mode 100644 src/test/resources/variant_entries.json create mode 100644 src/test/resources/variant_entry_single.json diff --git a/.gitignore b/.gitignore index 65e37ad..e21cc92 100644 --- a/.gitignore +++ b/.gitignore @@ -258,6 +258,8 @@ gradle-app.setting ### Gradle Patch ### **/build/ +sample/ + # End of https://www.toptal.com/developers/gitignore/api/macos,code-java,java-web,maven,gradle,intellij,visualstudiocode,eclipse .idea/compiler.xml .idea/encodings.xml diff --git a/pom.xml b/pom.xml index ab83569..8f48e99 100644 --- a/pom.xml +++ b/pom.xml @@ -115,6 +115,12 @@ json-simple ${json.simple.version} provided + + + junit + junit + + org.springframework @@ -134,6 +140,14 @@ prepare-agent + + + + sun/** + com/sun/** + jdk/** + + report diff --git a/src/main/java/com/contentstack/utils/Utils.java b/src/main/java/com/contentstack/utils/Utils.java index c11bf05..1acb7ee 100644 --- a/src/main/java/com/contentstack/utils/Utils.java +++ b/src/main/java/com/contentstack/utils/Utils.java @@ -23,15 +23,19 @@ public class Utils { - /** - * The `render` function takes a JSON object, an array of path strings, and an option object, and - * renders the contents of the JSON object based on the provided paths and options. + * The `render` function takes a JSON object, an array of path strings, and an + * option object, and + * renders the contents of the JSON object based on the provided paths and + * options. * - * @param entryObj The entryObj parameter is a JSONObject that represents an entry or a data + * @param entryObj The entryObj parameter is a JSONObject that represents an + * entry or a data * object. It contains various properties and values. - * @param pathString An array of strings representing the paths to the content in the JSON object. - * @param renderObject The `renderObject` parameter is an object of type `Option`. It is used to + * @param pathString An array of strings representing the paths to the content + * in the JSON object. + * @param renderObject The `renderObject` parameter is an object of type + * `Option`. It is used to * specify rendering options for the content. */ public static void render(JSONObject entryObj, String[] pathString, Option renderObject) { @@ -54,7 +58,8 @@ public static void render(JSONObject entryObj, String[] pathString, Option rende findContent(entryObj, path, callback); } } else { - // if pathString is not given, extract all available pathString from _embedded_items + // if pathString is not given, extract all available pathString from + // _embedded_items JSONObject embedKeys = entryObj.getJSONObject("_embedded_items"); ArrayList pathKeys = new ArrayList<>(embedKeys.keySet()); for (String path : pathKeys) { @@ -64,23 +69,31 @@ public static void render(JSONObject entryObj, String[] pathString, Option rende } } - /** - * The function takes a string, a JSON object, and an option, and replaces certain elements in the + * The function takes a string, a JSON object, and an option, and replaces + * certain elements in the * string with values from the JSON object based on the option. * - * @param rteStringify The `rteStringify` parameter is a string representation of the content to be - * rendered. It is passed to the `Jsoup.parse()` method to create a `Document` object. - * @param embedObject The `embedObject` parameter is a JSONObject that contains embedded items. It - * may have a key "_embedded_items" which holds a JSONObject of embedded items. - * @param option The "option" parameter is of type "Option". It is an object that represents a - * specific option for rendering the content. The exact structure and properties of the "Option" - * object are not provided in the code snippet, so it would be necessary to refer to the + * @param rteStringify The `rteStringify` parameter is a string representation + * of the content to be + * rendered. It is passed to the `Jsoup.parse()` method to + * create a `Document` object. + * @param embedObject The `embedObject` parameter is a JSONObject that contains + * embedded items. It + * may have a key "_embedded_items" which holds a JSONObject + * of embedded items. + * @param option The "option" parameter is of type "Option". It is an + * object that represents a + * specific option for rendering the content. The exact + * structure and properties of the "Option" + * object are not provided in the code snippet, so it would + * be necessary to refer to the * documentation or other parts of the code - * @return The method is returning the modified RTE (Rich Text Editor) content as a string. + * @return The method is returning the modified RTE (Rich Text Editor) content + * as a string. */ public static String renderContent(String rteStringify, JSONObject embedObject, Option option) { - final String[] sReplaceRTE = {rteStringify}; + final String[] sReplaceRTE = { rteStringify }; Document html = Jsoup.parse(rteStringify); getEmbeddedObjects(html, metadata -> { Optional filteredContent = Optional.empty(); @@ -99,14 +112,18 @@ public static String renderContent(String rteStringify, JSONObject embedObject, } /** - * The function takes an array of strings, an object, and an option, and returns a new array with the + * The function takes an array of strings, an object, and an option, and returns + * a new array with the * rendered contents of each string. * * @param rteArray An array of RTE (Rich Text Editor) content strings. - * @param entryObject The `entryObject` parameter is a JSONObject that contains the data needed for - * rendering the content. It likely contains key-value pairs representing different properties or + * @param entryObject The `entryObject` parameter is a JSONObject that contains + * the data needed for + * rendering the content. It likely contains key-value pairs + * representing different properties or * attributes of the content. - * @param option The "option" parameter is an object of type "Option". It is used as an argument in the + * @param option The "option" parameter is an object of type "Option". It + * is used as an argument in the * "renderContent" method. * @return The method is returning a JSONArray object. */ @@ -124,7 +141,9 @@ private static Optional findEmbeddedItems(JSONObject jsonObject, Met Set allKeys = jsonObject.keySet(); for (String key : allKeys) { JSONArray jsonArray = jsonObject.optJSONArray(key); - Optional filteredContent = StreamSupport.stream(jsonArray.spliterator(), false).map(val -> (JSONObject) val).filter(val -> val.optString("uid").equalsIgnoreCase(metadata.getItemUid())).findFirst(); + Optional filteredContent = StreamSupport.stream(jsonArray.spliterator(), false) + .map(val -> (JSONObject) val) + .filter(val -> val.optString("uid").equalsIgnoreCase(metadata.getItemUid())).findFirst(); if (filteredContent.isPresent()) { return filteredContent; } @@ -133,33 +152,47 @@ private static Optional findEmbeddedItems(JSONObject jsonObject, Met } /** - * The function converts a JSONArray to HTML using a specified key path and options. + * The function converts a JSONArray to HTML using a specified key path and + * options. * * @param entryArray A JSONArray containing JSON objects. - * @param keyPath The keyPath parameter is an array of strings that represents the path to a specific - * key in a JSON object. Each string in the array represents a key in the path. For example, if the - * keyPath is ["person", "name"], it means that we want to access the value of the " - * @param option The "option" parameter is an object of type "Option". It is used to specify additional - * options or settings for the JSON to HTML conversion process. + * @param keyPath The keyPath parameter is an array of strings that + * represents the path to a specific + * key in a JSON object. Each string in the array represents a + * key in the path. For example, if the + * keyPath is ["person", "name"], it means that we want to + * access the value of the " + * @param option The "option" parameter is an object of type "Option". It is + * used to specify additional + * options or settings for the JSON to HTML conversion + * process. */ public static void jsonToHTML(@NotNull JSONArray entryArray, @NotNull String[] keyPath, @NotNull Option option) { entryArray.forEach(jsonObj -> jsonToHTML((JSONObject) jsonObj, keyPath, option)); } - /** - * The function `jsonToHTML` converts a JSON object to HTML using a specified key path and + * The function `jsonToHTML` converts a JSON object to HTML using a specified + * key path and * rendering options. * - * @param entry The `entry` parameter is a `JSONObject` that represents the JSON data that you want - * to convert to HTML. It contains the data that you want to render as HTML. - * @param keyPath The keyPath parameter is an array of strings that represents the path to the - * desired content in the JSON object. Each string in the array represents a key in the JSON object - * hierarchy. The method will traverse the JSON object using the keys in the keyPath array to find + * @param entry The `entry` parameter is a `JSONObject` that represents + * the JSON data that you want + * to convert to HTML. It contains the data that you want to + * render as HTML. + * @param keyPath The keyPath parameter is an array of strings that + * represents the path to the + * desired content in the JSON object. Each string in the + * array represents a key in the JSON object + * hierarchy. The method will traverse the JSON object using + * the keys in the keyPath array to find * the desired content. - * @param renderOption The renderOption parameter is an option that determines how the content - * should be rendered. It is of type Option, which is likely an enum or a class with different - * rendering options. The specific options available and their meanings would depend on the + * @param renderOption The renderOption parameter is an option that determines + * how the content + * should be rendered. It is of type Option, which is likely + * an enum or a class with different + * rendering options. The specific options available and + * their meanings would depend on the * implementation of the Option class. */ public static void jsonToHTML(@NotNull JSONObject entry, @NotNull String[] keyPath, Option renderOption) { @@ -173,7 +206,6 @@ public static void jsonToHTML(@NotNull JSONObject entry, @NotNull String[] keyPa return Optional.empty(); }; - ContentCallback callback = content -> { if (content instanceof JSONArray) { JSONArray contentArray = (JSONArray) content; @@ -191,16 +223,21 @@ public static void jsonToHTML(@NotNull JSONObject entry, @NotNull String[] keyPa } } - /** - * The function converts a JSON object to HTML using a specified rendering option and optional embedded + * The function converts a JSON object to HTML using a specified rendering + * option and optional embedded * items. * - * @param jsonRTE A JSONObject representing the JSON data to be converted to HTML. - * @param renderOption The `renderOption` parameter is an option that determines how the JSON content - * should be rendered as HTML. It could be an enum or a class that defines different rendering options. - * @param embeddeditems The `embedded-items` parameter is a `JSONObject` that contains embedded items. - * It is used to find and retrieve embedded items based on their metadata. + * @param jsonRTE A JSONObject representing the JSON data to be converted + * to HTML. + * @param renderOption The `renderOption` parameter is an option that + * determines how the JSON content + * should be rendered as HTML. It could be an enum or a + * class that defines different rendering options. + * @param embeddeditems The `embedded-items` parameter is a `JSONObject` that + * contains embedded items. + * It is used to find and retrieve embedded items based on + * their metadata. * @return The method is returning a String. */ public static String jsonToHTML(@NotNull JSONObject jsonRTE, Option renderOption, JSONObject embeddeditems) { @@ -213,17 +250,22 @@ public static String jsonToHTML(@NotNull JSONObject jsonRTE, Option renderOption return enumerateContent(jsonRTE, renderOption, converter); } - /** - * The function `jsonToHTML` converts a JSON array to HTML using a specified rendering option and + * The function `jsonToHTML` converts a JSON array to HTML using a specified + * rendering option and * optional embedded items. * - * @param jsonRTE A JSONArray object containing the JSON data to be converted to HTML. - * @param renderOption The `renderOption` parameter is an option that determines how the JSON data - * should be rendered as HTML. It could be an enum or a custom class that defines different rendering + * @param jsonRTE A JSONArray object containing the JSON data to be + * converted to HTML. + * @param renderOption The `renderOption` parameter is an option that + * determines how the JSON data + * should be rendered as HTML. It could be an enum or a + * custom class that defines different rendering * options. - * @param embeddeditems The `embedded-items` parameter is a `JSONObject` that contains embedded items. - * It is used to find and retrieve embedded items based on the metadata provided. + * @param embeddeditems The `embedded-items` parameter is a `JSONObject` that + * contains embedded items. + * It is used to find and retrieve embedded items based on + * the metadata provided. * @return The method is returning an Object. */ public static Object jsonToHTML(@NotNull JSONArray jsonRTE, Option renderOption, JSONObject embeddeditems) { @@ -236,22 +278,118 @@ public static Object jsonToHTML(@NotNull JSONArray jsonRTE, Option renderOption, return enumerateContents(jsonRTE, renderOption, converter); } - /** - * The function takes a JSONArray, a keyPath array, and an Option object, and iterates over each + * The function takes a JSONArray, a keyPath array, and an Option object, and + * iterates over each * JSONObject in the JSONArray to call another render function. * - * @param jsonArray A JSONArray object that contains a collection of JSON objects. - * @param keyPath The `keyPath` parameter is an array of strings that represents the path to a specific - * key in a JSON object. Each string in the array represents a key in the path. For example, if the key + * @param jsonArray A JSONArray object that contains a collection of JSON + * objects. + * @param keyPath The `keyPath` parameter is an array of strings that + * represents the path to a specific + * key in a JSON object. Each string in the array represents + * a key in the path. For example, if the key * path is `["foo", "bar", "baz"]`, it means that you want - * @param renderObject The `renderObject` parameter is an object of type `Option`. + * @param renderObject The `renderObject` parameter is an object of type + * `Option`. */ public void render(@NotNull JSONArray jsonArray, @NotNull String[] keyPath, @NotNull Option renderObject) { jsonArray.forEach(jsonObj -> render((JSONObject) jsonObj, keyPath, renderObject)); } - //update assetURL in json of GQL response + public static JSONObject getVariantAliases(JSONObject entry, String contentTypeUid) { + if (contentTypeUid == null || contentTypeUid.isEmpty()) { + throw new IllegalArgumentException("ContentType is required."); + } + if (entry == null) { + throw new IllegalArgumentException("Entry must not be null."); + } + + if (!entry.has("uid") || entry.isNull("uid")) { + throw new IllegalArgumentException("Entry must contain uid."); + } + + String entryUid = entry.optString("uid", ""); + JSONArray variantsArray = extractVariantAliasesFromEntry(entry); + JSONObject result = new JSONObject(); + result.put("entry_uid", entryUid); + result.put("contenttype_uid", contentTypeUid); + result.put("variants", variantsArray); + return result; + + } + + public static JSONArray getVariantAliases(JSONArray entries, String contentTypeUid) { + if (contentTypeUid == null || contentTypeUid.isEmpty()) { + throw new IllegalArgumentException("ContentType is required."); + } + if (entries == null) { + return new JSONArray(); + } + JSONArray variantResults = new JSONArray(); + for (int i = 0; i < entries.length(); i++) { + JSONObject entry = entries.optJSONObject(i); + if (entry != null && entry.has("uid")) { + JSONObject singleResult = getVariantAliases(entry, contentTypeUid); + variantResults.put(singleResult); + } + } + return variantResults; + } + + public static JSONObject getDataCsvariantsAttribute(JSONObject entry, String contentTypeUid) { + + if (entry == null) { + JSONObject result = new JSONObject(); + result.put("data-csvariants", "[]"); + return result; + } + JSONArray entries = new JSONArray(); + entries.put(entry); + return getDataCsvariantsAttribute(entries, contentTypeUid); + } + + public static JSONObject getDataCsvariantsAttribute(JSONArray entries, String contentTypeUid) { + + JSONObject result = new JSONObject(); + if (entries == null) { + result.put("data-csvariants", "[]"); + return result; + } + if (contentTypeUid == null || contentTypeUid.isEmpty()) { + throw new IllegalArgumentException("ContentType is required."); + } + + JSONArray variantResults = getVariantAliases(entries, contentTypeUid); + String resultString = variantResults.toString(); + result.put("data-csvariants", resultString); + return result; + } + + private static JSONArray extractVariantAliasesFromEntry(JSONObject entry) { + JSONArray variantArray = new JSONArray(); + JSONObject publishDetails = entry.optJSONObject("publish_details"); + if (publishDetails == null) { + return new JSONArray(); + } + JSONObject variants = publishDetails.optJSONObject("variants"); + if (variants == null) { + return new JSONArray(); + } + + for (String key : variants.keySet()) { + Object value = variants.get(key); + if (value instanceof JSONObject) { + String alias = ((JSONObject) value).optString("alias", ""); + if (alias != null && !alias.isEmpty()) { + variantArray.put(alias.trim()); + } + } + } + return variantArray; + } + + // update assetURL in json of GQL response public static void UpdateAssetURLForGQL(JSONObject entryJson) { Map assetUrls = new HashMap<>(); if (entryJson.has("data")) { @@ -278,7 +416,8 @@ public static void UpdateAssetURLForGQL(JSONObject entryJson) { String url = nodeList.getString("url"); if (nodeList.has("system")) { JSONObject systemList = nodeList.getJSONObject("system"); - if ("sys_assets".equals(systemList.optString("content_type_uid")) && systemList.has("uid")) { + if ("sys_assets".equals(systemList.optString("content_type_uid")) + && systemList.has("uid")) { String uid = systemList.getString("uid"); assetUrls.put(uid, url); updateChildObjects(entryJson, assetUrls); @@ -288,10 +427,9 @@ public static void UpdateAssetURLForGQL(JSONObject entryJson) { } } } - } - else - { - throw new IllegalArgumentException("_embedded_items not present in entry. Call includeEmbeddedItems() before fetching entry."); + } else { + throw new IllegalArgumentException( + "_embedded_items not present in entry. Call includeEmbeddedItems() before fetching entry."); } } } @@ -342,5 +480,3 @@ private static void updateChildrenArray(JSONArray childrenArray, Map", assetLink.opt("assetlink").toString()); } } diff --git a/src/test/java/com/contentstack/utils/ReadResource.java b/src/test/java/com/contentstack/utils/ReadResource.java index 607a294..c2cce7c 100644 --- a/src/test/java/com/contentstack/utils/ReadResource.java +++ b/src/test/java/com/contentstack/utils/ReadResource.java @@ -16,8 +16,6 @@ public class ReadResource { public JSONObject readJson(String filename) throws IOException { File file = new File(filename); - String absolutePath = file.getAbsolutePath(); - System.out.println(absolutePath); BufferedReader reader = new BufferedReader(new FileReader(file)); StringBuilder stringBuilder = new StringBuilder(); char[] buffer = new char[10]; diff --git a/src/test/java/com/contentstack/utils/TestRte.java b/src/test/java/com/contentstack/utils/TestRte.java index cea24dd..a3bb259 100644 --- a/src/test/java/com/contentstack/utils/TestRte.java +++ b/src/test/java/com/contentstack/utils/TestRte.java @@ -120,7 +120,6 @@ public void testAffectedEntry() throws IOException { final String rte = "src/test/resources/reports/wfs.json"; JSONObject theRTE = new ReadResource().readJson(rte); String result = Utils.jsonToHTML(theRTE, new DefaultOption(), null); - System.out.println(result); Assert.assertEquals(kWFSAffectedHtml, result); } @@ -130,7 +129,6 @@ public void testOne() throws IOException { final String rte = "src/test/resources/reports/one.json"; JSONObject theRTE = new ReadResource().readJson(rte); String result = Utils.jsonToHTML(theRTE, new DefaultOption(), null); - System.out.println(result); Assert.assertEquals(kONEHtml, result); } @@ -139,7 +137,6 @@ public void testOCT7Issue() throws IOException { final String rte = "src/test/resources/reports/oct_7.json"; JSONObject theRTE = new ReadResource().readJson(rte); String result = Utils.jsonToHTML(theRTE, new DefaultOption(), null); - System.out.println(result); // Assert.assertEquals(kONEHtml, result); } @@ -148,7 +145,6 @@ public void testIssueOct() throws IOException { final String rte = "src/test/resources/reports/issue_oct.json"; JSONObject theRTE = new ReadResource().readJson(rte); String result = Utils.jsonToHTML(theRTE, new DefaultOption(), null); - System.out.println(result); // Assert.assertEquals(kONEHtml, result); } diff --git a/src/test/java/com/contentstack/utils/UtilTests.java b/src/test/java/com/contentstack/utils/UtilTests.java index fa4359b..445b2e1 100644 --- a/src/test/java/com/contentstack/utils/UtilTests.java +++ b/src/test/java/com/contentstack/utils/UtilTests.java @@ -1,13 +1,18 @@ package com.contentstack.utils; import com.contentstack.utils.render.DefaultOption; +import org.json.JSONArray; import org.json.JSONObject; +import org.junit.Assert; import org.junit.BeforeClass; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runners.MethodSorters; import java.io.IOException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -173,6 +178,129 @@ public void testUpdateAssetUrl() throws IOException{ // System.out.println(localJsonObj1); } + private static Set jsonArrayToStringSet(JSONArray arr) { + Set set = new HashSet<>(); + for (int i = 0; i < arr.length(); i++) { + set.add(arr.getString(i)); + } + return set; + } + + @Test + public void testGetVariantAliasesSingleEntry() throws IOException { + final String json = "src/test/resources/variant_entry_single.json"; + JSONObject full = new ReadResource().readJson(json); + JSONObject entry = full.getJSONObject("entry"); + String contentTypeUid = "movie"; + + JSONObject result = Utils.getVariantAliases(entry, contentTypeUid); + + Assert.assertTrue(result.has("entry_uid") && !result.getString("entry_uid").isEmpty()); + Assert.assertEquals(contentTypeUid, result.getString("contenttype_uid")); + JSONArray variants = result.getJSONArray("variants"); + Assert.assertNotNull(variants); + Set aliasSet = jsonArrayToStringSet(variants); + Assert.assertEquals( + new HashSet<>(Arrays.asList("cs_personalize_0_0", "cs_personalize_0_3")), + aliasSet); + } + + @Test + public void testGetDataCsvariantsAttributeSingleEntry() throws IOException { + final String json = "src/test/resources/variant_entry_single.json"; + JSONObject full = new ReadResource().readJson(json); + JSONObject entry = full.getJSONObject("entry"); + String contentTypeUid = "movie"; + + JSONObject result = Utils.getDataCsvariantsAttribute(entry, contentTypeUid); + + Assert.assertTrue(result.has("data-csvariants")); + String dataCsvariantsStr = result.getString("data-csvariants"); + JSONArray arr = new JSONArray(dataCsvariantsStr); + Assert.assertEquals(1, arr.length()); + JSONObject first = arr.getJSONObject(0); + Assert.assertTrue(first.has("entry_uid") && !first.getString("entry_uid").isEmpty()); + Assert.assertEquals(contentTypeUid, first.getString("contenttype_uid")); + Set aliasSet = jsonArrayToStringSet(first.getJSONArray("variants")); + Assert.assertEquals( + new HashSet<>(Arrays.asList("cs_personalize_0_0", "cs_personalize_0_3")), + aliasSet); + } + + @Test + public void testGetVariantAliasesMultipleEntries() throws IOException { + final String json = "src/test/resources/variant_entries.json"; + JSONObject full = new ReadResource().readJson(json); + JSONArray entries = full.getJSONArray("entries"); + String contentTypeUid = "movie"; + + JSONArray result = Utils.getVariantAliases(entries, contentTypeUid); + + Assert.assertNotNull(result); + Assert.assertEquals(3, result.length()); + JSONObject first = result.getJSONObject(0); + Assert.assertTrue(first.has("entry_uid") && !first.getString("entry_uid").isEmpty()); + Assert.assertEquals(contentTypeUid, first.getString("contenttype_uid")); + Set firstSet = jsonArrayToStringSet(first.getJSONArray("variants")); + Assert.assertEquals(new HashSet<>(Arrays.asList("cs_personalize_0_0", "cs_personalize_0_3")), firstSet); + JSONObject second = result.getJSONObject(1); + Assert.assertTrue(second.has("entry_uid") && !second.getString("entry_uid").isEmpty()); + Assert.assertEquals(1, second.getJSONArray("variants").length()); + Assert.assertEquals("cs_personalize_0_0", second.getJSONArray("variants").getString(0)); + JSONObject third = result.getJSONObject(2); + Assert.assertTrue(third.has("entry_uid") && !third.getString("entry_uid").isEmpty()); + Assert.assertEquals(0, third.getJSONArray("variants").length()); + } + + @Test + public void testGetDataCsvariantsAttributeMultipleEntries() throws IOException { + final String json = "src/test/resources/variant_entries.json"; + JSONObject full = new ReadResource().readJson(json); + JSONArray entries = full.getJSONArray("entries"); + String contentTypeUid = "movie"; + + JSONObject result = Utils.getDataCsvariantsAttribute(entries, contentTypeUid); + + Assert.assertTrue(result.has("data-csvariants")); + String dataCsvariantsStr = result.getString("data-csvariants"); + JSONArray arr = new JSONArray(dataCsvariantsStr); + Assert.assertEquals(3, arr.length()); + Assert.assertTrue(arr.getJSONObject(0).has("entry_uid") && !arr.getJSONObject(0).getString("entry_uid").isEmpty()); + Assert.assertEquals(2, arr.getJSONObject(0).getJSONArray("variants").length()); + Assert.assertTrue(arr.getJSONObject(1).has("entry_uid") && !arr.getJSONObject(1).getString("entry_uid").isEmpty()); + Assert.assertEquals(1, arr.getJSONObject(1).getJSONArray("variants").length()); + Assert.assertTrue(arr.getJSONObject(2).has("entry_uid") && !arr.getJSONObject(2).getString("entry_uid").isEmpty()); + Assert.assertEquals(0, arr.getJSONObject(2).getJSONArray("variants").length()); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetVariantAliasesThrowsWhenEntryNull() { + Utils.getVariantAliases((JSONObject) null, "landing_page"); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetVariantAliasesThrowsWhenContentTypeUidNull() throws IOException { + final String json = "src/test/resources/variant_entry_single.json"; + JSONObject full = new ReadResource().readJson(json); + JSONObject entry = full.getJSONObject("entry"); + Utils.getVariantAliases(entry, null); + } + + @Test(expected = IllegalArgumentException.class) + public void testGetVariantAliasesThrowsWhenContentTypeUidEmpty() throws IOException { + final String json = "src/test/resources/variant_entry_single.json"; + JSONObject full = new ReadResource().readJson(json); + JSONObject entry = full.getJSONObject("entry"); + Utils.getVariantAliases(entry, ""); + } + + @Test + public void testGetDataCsvariantsAttributeWhenEntryNull() { + JSONObject result = Utils.getDataCsvariantsAttribute((JSONObject) null, "landing_page"); + Assert.assertTrue(result.has("data-csvariants")); + Assert.assertEquals("[]", result.getString("data-csvariants")); + } + } diff --git a/src/test/resources/variant_entries.json b/src/test/resources/variant_entries.json new file mode 100644 index 0000000..34f6c9f --- /dev/null +++ b/src/test/resources/variant_entries.json @@ -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" + } + } + ] +} diff --git a/src/test/resources/variant_entry_single.json b/src/test/resources/variant_entry_single.json new file mode 100644 index 0000000..57e92ff --- /dev/null +++ b/src/test/resources/variant_entry_single.json @@ -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 + } + } + } + } +} From 34134eb998af66da0ba3b438756065ddc0107289 Mon Sep 17 00:00:00 2001 From: reeshika-h Date: Tue, 17 Mar 2026 19:31:32 +0530 Subject: [PATCH 2/3] license updated --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index d78b6bc..c2a603d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2012 - 2025 Contentstack +Copyright (c) 2012 - 2026 Contentstack Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From d73c36a3d083913f61a1322ae90d567a58f81769 Mon Sep 17 00:00:00 2001 From: reeshika-h Date: Wed, 18 Mar 2026 13:22:27 +0530 Subject: [PATCH 3/3] version bump --- Changelog.md | 6 ++++++ pom.xml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index 550e08f..b9c0f02 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,6 +1,12 @@ # Changelog A brief description of what changes project contains +## Mar 23, 2026 + +#### v1.3.0 + +- Enhancement: Variant Utility + ## Mar 17, 2025 #### v1.2.15 diff --git a/pom.xml b/pom.xml index 8f48e99..c6dd1fd 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.contentstack.sdk utils - 1.2.15 + 1.3.0 jar Contentstack-utils Java Utils SDK for Contentstack Content Delivery API, Contentstack is a headless CMS