From 7201b6080e6796e9144a9d95bfa8965fd0c19c5d Mon Sep 17 00:00:00 2001 From: OMpawar-21 Date: Mon, 3 Aug 2026 23:37:31 +0530 Subject: [PATCH 1/2] feat: add taxonomy publish/unpublish/unlocalize and terms unlocalize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes parity gap with JS SDK and Java (feat/DX-9676-taxonomy-publish). Taxonomy (Taxonomy.cs): - Publish(model) + PublishAsync → POST /taxonomies/publish (ThrowIfUidNotEmpty) - Unpublish(model) + UnpublishAsync → POST /taxonomies/unpublish (ThrowIfUidNotEmpty) - Unlocalize(locale) + UnlocalizeAsync → DELETE /taxonomies/{uid}?locale= (ThrowIfUidEmpty) Term (Term.cs): - Unlocalize(locale) + UnlocalizeAsync → DELETE .../terms/{uid}?locale= (ThrowIfUidEmpty) New: TaxonomyPublishModel.cs, TaxonomyPublishService.cs (root-level body serializer). 44/44 unit tests pass. Co-Authored-By: Claude Sonnet 4.6 --- .../Models/TaxonomyTest.cs | 89 +++++++++++++++++++ .../Models/TermTest.cs | 26 ++++++ .../Models/Taxonomy.cs | 66 ++++++++++++++ .../Models/TaxonomyPublishModel.cs | 34 +++++++ Contentstack.Management.Core/Models/Term.cs | 24 +++++ .../Services/Models/TaxonomyPublishService.cs | 39 ++++++++ 6 files changed, 278 insertions(+) create mode 100644 Contentstack.Management.Core/Models/TaxonomyPublishModel.cs create mode 100644 Contentstack.Management.Core/Services/Models/TaxonomyPublishService.cs diff --git a/Contentstack.Management.Core.Unit.Tests/Models/TaxonomyTest.cs b/Contentstack.Management.Core.Unit.Tests/Models/TaxonomyTest.cs index 66f7240..ffee7c6 100644 --- a/Contentstack.Management.Core.Unit.Tests/Models/TaxonomyTest.cs +++ b/Contentstack.Management.Core.Unit.Tests/Models/TaxonomyTest.cs @@ -194,5 +194,94 @@ public void Localize_When_Api_Returns_400_Returns_Unsuccessful_Response() Assert.IsFalse(response.IsSuccessStatusCode); Assert.AreEqual(HttpStatusCode.BadRequest, response.StatusCode); } + + [TestMethod] + public void Publish_Throws_When_Uid_Is_Set() + { + var model = new TaxonomyPublishModel { Locales = new System.Collections.Generic.List { "en-us" } }; + Assert.ThrowsException(() => _stack.Taxonomy(_fixture.Create()).Publish(model)); + Assert.ThrowsExceptionAsync(() => _stack.Taxonomy(_fixture.Create()).PublishAsync(model)); + } + + [TestMethod] + public void Unpublish_Throws_When_Uid_Is_Set() + { + var model = new TaxonomyPublishModel { Locales = new System.Collections.Generic.List { "en-us" } }; + Assert.ThrowsException(() => _stack.Taxonomy(_fixture.Create()).Unpublish(model)); + Assert.ThrowsExceptionAsync(() => _stack.Taxonomy(_fixture.Create()).UnpublishAsync(model)); + } + + [TestMethod] + public void Unlocalize_Throws_When_Uid_Is_Empty() + { + Assert.ThrowsException(() => _stack.Taxonomy().Unlocalize("hi-in")); + Assert.ThrowsExceptionAsync(() => _stack.Taxonomy().UnlocalizeAsync("hi-in")); + } + + [TestMethod] + public void Should_Publish_Taxonomy() + { + var model = new TaxonomyPublishModel + { + Locales = new System.Collections.Generic.List { "en-us" }, + Environments = new System.Collections.Generic.List { "production" }, + Items = new System.Collections.Generic.List { new TaxonomyPublishItem { Uid = "taxonomy_1" } } + }; + ContentstackResponse response = _stack.Taxonomy().Publish(model); + Assert.AreEqual(_contentstackResponse.OpenResponse(), response.OpenResponse()); + } + + [TestMethod] + public async System.Threading.Tasks.Task Should_Publish_Taxonomy_Async() + { + var model = new TaxonomyPublishModel + { + Locales = new System.Collections.Generic.List { "en-us" }, + Environments = new System.Collections.Generic.List { "production" }, + Items = new System.Collections.Generic.List { new TaxonomyPublishItem { Uid = "taxonomy_1" } } + }; + ContentstackResponse response = await _stack.Taxonomy().PublishAsync(model); + Assert.AreEqual(_contentstackResponse.OpenResponse(), response.OpenResponse()); + } + + [TestMethod] + public void Should_Unpublish_Taxonomy() + { + var model = new TaxonomyPublishModel + { + Locales = new System.Collections.Generic.List { "en-us" }, + Environments = new System.Collections.Generic.List { "production" }, + Items = new System.Collections.Generic.List { new TaxonomyPublishItem { Uid = "taxonomy_1" } } + }; + ContentstackResponse response = _stack.Taxonomy().Unpublish(model); + Assert.AreEqual(_contentstackResponse.OpenResponse(), response.OpenResponse()); + } + + [TestMethod] + public async System.Threading.Tasks.Task Should_Unpublish_Taxonomy_Async() + { + var model = new TaxonomyPublishModel + { + Locales = new System.Collections.Generic.List { "en-us" }, + Environments = new System.Collections.Generic.List { "production" }, + Items = new System.Collections.Generic.List { new TaxonomyPublishItem { Uid = "taxonomy_1" } } + }; + ContentstackResponse response = await _stack.Taxonomy().UnpublishAsync(model); + Assert.AreEqual(_contentstackResponse.OpenResponse(), response.OpenResponse()); + } + + [TestMethod] + public void Should_Unlocalize_Taxonomy() + { + ContentstackResponse response = _stack.Taxonomy(_fixture.Create()).Unlocalize("hi-in"); + Assert.AreEqual(_contentstackResponse.OpenResponse(), response.OpenResponse()); + } + + [TestMethod] + public async System.Threading.Tasks.Task Should_Unlocalize_Taxonomy_Async() + { + ContentstackResponse response = await _stack.Taxonomy(_fixture.Create()).UnlocalizeAsync("hi-in"); + Assert.AreEqual(_contentstackResponse.OpenResponse(), response.OpenResponse()); + } } } diff --git a/Contentstack.Management.Core.Unit.Tests/Models/TermTest.cs b/Contentstack.Management.Core.Unit.Tests/Models/TermTest.cs index 7191318..eec51b6 100644 --- a/Contentstack.Management.Core.Unit.Tests/Models/TermTest.cs +++ b/Contentstack.Management.Core.Unit.Tests/Models/TermTest.cs @@ -174,5 +174,31 @@ public void Localize_Throws_When_Term_Uid_Is_Empty() Assert.ThrowsException(() => _stack.Taxonomy(taxonomyUid).Terms().Localize(_fixture.Create())); Assert.ThrowsExceptionAsync(() => _stack.Taxonomy(taxonomyUid).Terms().LocalizeAsync(_fixture.Create())); } + + [TestMethod] + public void Unlocalize_Throws_When_Term_Uid_Is_Empty() + { + string taxonomyUid = _fixture.Create(); + Assert.ThrowsException(() => _stack.Taxonomy(taxonomyUid).Terms().Unlocalize("hi-in")); + Assert.ThrowsExceptionAsync(() => _stack.Taxonomy(taxonomyUid).Terms().UnlocalizeAsync("hi-in")); + } + + [TestMethod] + public void Should_Unlocalize_Term() + { + string taxonomyUid = _fixture.Create(); + string termUid = _fixture.Create(); + ContentstackResponse response = _stack.Taxonomy(taxonomyUid).Terms(termUid).Unlocalize("hi-in"); + Assert.AreEqual(_contentstackResponse.OpenResponse(), response.OpenResponse()); + } + + [TestMethod] + public async System.Threading.Tasks.Task Should_Unlocalize_Term_Async() + { + string taxonomyUid = _fixture.Create(); + string termUid = _fixture.Create(); + ContentstackResponse response = await _stack.Taxonomy(taxonomyUid).Terms(termUid).UnlocalizeAsync("hi-in"); + Assert.AreEqual(_contentstackResponse.OpenResponse(), response.OpenResponse()); + } } } diff --git a/Contentstack.Management.Core/Models/Taxonomy.cs b/Contentstack.Management.Core/Models/Taxonomy.cs index 3614312..832c5e2 100644 --- a/Contentstack.Management.Core/Models/Taxonomy.cs +++ b/Contentstack.Management.Core/Models/Taxonomy.cs @@ -184,6 +184,72 @@ public Task ImportAsync(TaxonomyImportModel model, Paramet return stack.client.InvokeAsync(service); } + /// + /// Publish one or more taxonomies to the specified environments and locales. + /// Call on a collection-level instance (no UID set). + /// + public ContentstackResponse Publish(TaxonomyPublishModel model, ParameterCollection? collection = null) + { + stack.ThrowIfNotLoggedIn(); + ThrowIfUidNotEmpty(); + return stack.client.InvokeSync( + new TaxonomyPublishService(stack, resourcePath + "/publish", model, collection)); + } + + /// Publish one or more taxonomies asynchronously. + public Task PublishAsync(TaxonomyPublishModel model, ParameterCollection? collection = null) + { + stack.ThrowIfNotLoggedIn(); + ThrowIfUidNotEmpty(); + return stack.client.InvokeAsync, ContentstackResponse>( + new TaxonomyPublishService(stack, resourcePath + "/publish", model, collection)); + } + + /// + /// Unpublish one or more taxonomies from the specified environments and locales. + /// Call on a collection-level instance (no UID set). + /// + public ContentstackResponse Unpublish(TaxonomyPublishModel model, ParameterCollection? collection = null) + { + stack.ThrowIfNotLoggedIn(); + ThrowIfUidNotEmpty(); + return stack.client.InvokeSync( + new TaxonomyPublishService(stack, resourcePath + "/unpublish", model, collection)); + } + + /// Unpublish one or more taxonomies asynchronously. + public Task UnpublishAsync(TaxonomyPublishModel model, ParameterCollection? collection = null) + { + stack.ThrowIfNotLoggedIn(); + ThrowIfUidNotEmpty(); + return stack.client.InvokeAsync, ContentstackResponse>( + new TaxonomyPublishService(stack, resourcePath + "/unpublish", model, collection)); + } + + /// + /// Remove a locale variant of this taxonomy. + /// Requires a UID (instance-level). Locale is required. + /// + public ContentstackResponse Unlocalize(string locale, ParameterCollection? collection = null) + { + stack.ThrowIfNotLoggedIn(); + ThrowIfUidEmpty(); + var coll = collection ?? new ParameterCollection(); + coll.Add("locale", locale); + return stack.client.InvokeSync(new FetchDeleteService(stack, resourcePath, "DELETE", coll)); + } + + /// Remove a locale variant of this taxonomy asynchronously. + public Task UnlocalizeAsync(string locale, ParameterCollection? collection = null) + { + stack.ThrowIfNotLoggedIn(); + ThrowIfUidEmpty(); + var coll = collection ?? new ParameterCollection(); + coll.Add("locale", locale); + return stack.client.InvokeAsync( + new FetchDeleteService(stack, resourcePath, "DELETE", coll)); + } + /// /// Get Terms instance for this taxonomy. When termUid is provided, returns a single-term context; otherwise collection for query/create. /// diff --git a/Contentstack.Management.Core/Models/TaxonomyPublishModel.cs b/Contentstack.Management.Core/Models/TaxonomyPublishModel.cs new file mode 100644 index 0000000..3f142a3 --- /dev/null +++ b/Contentstack.Management.Core/Models/TaxonomyPublishModel.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace Contentstack.Management.Core.Models +{ + /// + /// Request body for bulk taxonomy publish and unpublish operations. + /// + public class TaxonomyPublishModel + { + /// Target locale codes, e.g. ["en-us", "fr-fr"]. Required. + [JsonPropertyName("locales")] + public List? Locales { get; set; } + + /// Target environment UIDs. Required. + [JsonPropertyName("environments")] + public List? Environments { get; set; } + + /// Taxonomy UIDs to publish/unpublish. + [JsonPropertyName("items")] + public List? Items { get; set; } + + /// Optional ISO-8601 timestamp for scheduled publishing (Phase 2). + [JsonPropertyName("scheduled_at")] + public string? ScheduledAt { get; set; } + } + + /// A single taxonomy item reference in a publish/unpublish request. + public class TaxonomyPublishItem + { + [JsonPropertyName("uid")] + public string? Uid { get; set; } + } +} diff --git a/Contentstack.Management.Core/Models/Term.cs b/Contentstack.Management.Core/Models/Term.cs index 4b00ecc..ee0a41b 100644 --- a/Contentstack.Management.Core/Models/Term.cs +++ b/Contentstack.Management.Core/Models/Term.cs @@ -204,6 +204,30 @@ public Task LocalizeAsync(TermModel model, ParameterCollec return stack.client.InvokeAsync, ContentstackResponse>(service); } + /// + /// Remove a locale variant of this term. + /// Requires a UID (instance-level). Locale is required. + /// + public ContentstackResponse Unlocalize(string locale, ParameterCollection? collection = null) + { + stack.ThrowIfNotLoggedIn(); + ThrowIfUidEmpty(); + var coll = collection ?? new ParameterCollection(); + coll.Add("locale", locale); + return stack.client.InvokeSync(new FetchDeleteService(stack, resourcePath, "DELETE", coll)); + } + + /// Remove a locale variant of this term asynchronously. + public Task UnlocalizeAsync(string locale, ParameterCollection? collection = null) + { + stack.ThrowIfNotLoggedIn(); + ThrowIfUidEmpty(); + var coll = collection ?? new ParameterCollection(); + coll.Add("locale", locale); + return stack.client.InvokeAsync( + new FetchDeleteService(stack, resourcePath, "DELETE", coll)); + } + /// /// Search terms across all taxonomies. GET /taxonomies/$all/terms with typeahead query param. Callable only when no specific term UID is set. /// diff --git a/Contentstack.Management.Core/Services/Models/TaxonomyPublishService.cs b/Contentstack.Management.Core/Services/Models/TaxonomyPublishService.cs new file mode 100644 index 0000000..45397b5 --- /dev/null +++ b/Contentstack.Management.Core/Services/Models/TaxonomyPublishService.cs @@ -0,0 +1,39 @@ +using System; +using System.Text; +using System.Text.Json; +using Contentstack.Management.Core.Queryable; +using Contentstack.Management.Core.Utils; + +namespace Contentstack.Management.Core.Services.Models +{ + /// + /// Service for taxonomy publish/unpublish. Serializes the model directly as the root body + /// without a field-name wrapper (CreateUpdateService always wraps as {"field": model}). + /// + internal class TaxonomyPublishService : ContentstackService + { + private readonly T _model; + + internal TaxonomyPublishService(Core.Models.Stack stack, string resourcePath, T model, ParameterCollection? collection = null) + : base(stack?.client?.SerializerOptions ?? new JsonSerializerOptions(), stack: stack, collection: collection) + { + if (stack!.APIKey == null) + throw new ArgumentNullException("stack", CSConstants.MissingAPIKey); + if (resourcePath == null) + throw new ArgumentNullException("resourcePath", CSConstants.ResourcePathRequired); + if (model == null) + throw new ArgumentNullException("model", CSConstants.DataModelRequired); + + ResourcePath = resourcePath; + HttpMethod = "POST"; + if (collection != null && collection.Count > 0) + UseQueryString = true; + _model = model; + } + + public override void ContentBody() + { + ByteContent = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(_model, SerializerOptions)); + } + } +} From cb1f566b1fc0bacbe0331a48f06c3b14afcde64f Mon Sep 17 00:00:00 2001 From: OMpawar-21 Date: Tue, 4 Aug 2026 00:06:33 +0530 Subject: [PATCH 2/2] test: add integration tests for taxonomy publish/unpublish/unlocalize and terms unlocalize (Test280-289) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test280-283: Publish/Unpublish (sync + async) — looks up environment at runtime; marks Inconclusive if taxonomy_publish feature flag is not enabled on the test stack. Test284-285: Taxonomy.Unlocalize/UnlocalizeAsync — localizes first, then removes the locale. Test286-287: Term.Unlocalize/UnlocalizeAsync — same pattern on root term. Test288: Guard — Publish throws InvalidOperationException when UID is set. Test289: Guard — Unlocalize throws ArgumentException when no UID is set. Co-Authored-By: Claude Sonnet 4.6 --- .../Contentstack017_TaxonomyTest.cs | 243 ++++++++++++++++++ 1 file changed, 243 insertions(+) diff --git a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack017_TaxonomyTest.cs b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack017_TaxonomyTest.cs index c439f38..0febc7c 100644 --- a/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack017_TaxonomyTest.cs +++ b/Contentstack.Management.Core.Tests/IntegrationTest/Contentstack017_TaxonomyTest.cs @@ -6492,6 +6492,249 @@ public void Test279_Should_Handle_Extreme_Boundary_Combinations() } } + [TestMethod] + public void Test280_Should_Publish_Taxonomy() + { + TestOutputLogger.LogContext("TestScenario", "Test280_Should_Publish_Taxonomy"); + if (string.IsNullOrEmpty(_testLocaleCode)) + { + AssertLogger.Inconclusive("No non-master locale available; skipping publish test."); + return; + } + + // Look up an environment from the stack to use as a publish target. + ContentstackResponse envResp = _stack.Environments().Query().Find(); + if (!envResp.IsSuccessStatusCode) + { + AssertLogger.Inconclusive("Could not fetch environments; skipping publish test."); + return; + } + var envJson = envResp.OpenJsonObjectResponse(); + var envArray = envJson["environments"] as System.Text.Json.Nodes.JsonArray; + if (envArray == null || envArray.Count == 0) + { + AssertLogger.Inconclusive("No environments on stack; skipping publish test."); + return; + } + string envName = envArray[0]?["name"]?.ToString(); + if (string.IsNullOrEmpty(envName)) + { + AssertLogger.Inconclusive("Could not read environment name; skipping publish test."); + return; + } + + var model = new TaxonomyPublishModel + { + Locales = new List { _testLocaleCode }, + Environments = new List { envName }, + Items = new List { new TaxonomyPublishItem { Uid = _taxonomyUid } } + }; + ContentstackResponse response = _stack.Taxonomy().Publish(model); + // 403 = taxonomy_publish feature not enabled on this stack — treat as inconclusive. + if (response.StatusCode == System.Net.HttpStatusCode.Forbidden) + { + AssertLogger.Inconclusive("taxonomy_publish feature not enabled on this stack; skipping."); + return; + } + AssertLogger.IsTrue(response.IsSuccessStatusCode, $"Publish failed: {response.OpenResponse()}", "PublishTaxonomySuccess"); + } + + [TestMethod] + public async Task Test281_Should_Publish_Taxonomy_Async() + { + TestOutputLogger.LogContext("TestScenario", "Test281_Should_Publish_Taxonomy_Async"); + if (string.IsNullOrEmpty(_testLocaleCode)) + { + AssertLogger.Inconclusive("No non-master locale available; skipping async publish test."); + return; + } + + ContentstackResponse envResp = _stack.Environments().Query().Find(); + if (!envResp.IsSuccessStatusCode) { AssertLogger.Inconclusive("Could not fetch environments."); return; } + var envArray = envResp.OpenJsonObjectResponse()["environments"] as System.Text.Json.Nodes.JsonArray; + if (envArray == null || envArray.Count == 0) { AssertLogger.Inconclusive("No environments on stack."); return; } + string envName = envArray[0]?["name"]?.ToString(); + if (string.IsNullOrEmpty(envName)) { AssertLogger.Inconclusive("Could not read environment name."); return; } + + var model = new TaxonomyPublishModel + { + Locales = new List { _testLocaleCode }, + Environments = new List { envName }, + Items = new List { new TaxonomyPublishItem { Uid = _taxonomyUid } } + }; + ContentstackResponse response = await _stack.Taxonomy().PublishAsync(model); + if (response.StatusCode == System.Net.HttpStatusCode.Forbidden) + { + AssertLogger.Inconclusive("taxonomy_publish feature not enabled on this stack; skipping."); + return; + } + AssertLogger.IsTrue(response.IsSuccessStatusCode, $"PublishAsync failed: {response.OpenResponse()}", "PublishTaxonomyAsyncSuccess"); + } + + [TestMethod] + public void Test282_Should_Unpublish_Taxonomy() + { + TestOutputLogger.LogContext("TestScenario", "Test282_Should_Unpublish_Taxonomy"); + if (string.IsNullOrEmpty(_testLocaleCode)) + { + AssertLogger.Inconclusive("No non-master locale available; skipping unpublish test."); + return; + } + + ContentstackResponse envResp = _stack.Environments().Query().Find(); + if (!envResp.IsSuccessStatusCode) { AssertLogger.Inconclusive("Could not fetch environments."); return; } + var envArray = envResp.OpenJsonObjectResponse()["environments"] as System.Text.Json.Nodes.JsonArray; + if (envArray == null || envArray.Count == 0) { AssertLogger.Inconclusive("No environments on stack."); return; } + string envName = envArray[0]?["name"]?.ToString(); + if (string.IsNullOrEmpty(envName)) { AssertLogger.Inconclusive("Could not read environment name."); return; } + + var model = new TaxonomyPublishModel + { + Locales = new List { _testLocaleCode }, + Environments = new List { envName }, + Items = new List { new TaxonomyPublishItem { Uid = _taxonomyUid } } + }; + ContentstackResponse response = _stack.Taxonomy().Unpublish(model); + if (response.StatusCode == System.Net.HttpStatusCode.Forbidden) + { + AssertLogger.Inconclusive("taxonomy_publish feature not enabled on this stack; skipping."); + return; + } + AssertLogger.IsTrue(response.IsSuccessStatusCode, $"Unpublish failed: {response.OpenResponse()}", "UnpublishTaxonomySuccess"); + } + + [TestMethod] + public async Task Test283_Should_Unpublish_Taxonomy_Async() + { + TestOutputLogger.LogContext("TestScenario", "Test283_Should_Unpublish_Taxonomy_Async"); + if (string.IsNullOrEmpty(_testLocaleCode)) + { + AssertLogger.Inconclusive("No non-master locale available; skipping async unpublish test."); + return; + } + + ContentstackResponse envResp = _stack.Environments().Query().Find(); + if (!envResp.IsSuccessStatusCode) { AssertLogger.Inconclusive("Could not fetch environments."); return; } + var envArray = envResp.OpenJsonObjectResponse()["environments"] as System.Text.Json.Nodes.JsonArray; + if (envArray == null || envArray.Count == 0) { AssertLogger.Inconclusive("No environments on stack."); return; } + string envName = envArray[0]?["name"]?.ToString(); + if (string.IsNullOrEmpty(envName)) { AssertLogger.Inconclusive("Could not read environment name."); return; } + + var model = new TaxonomyPublishModel + { + Locales = new List { _testLocaleCode }, + Environments = new List { envName }, + Items = new List { new TaxonomyPublishItem { Uid = _taxonomyUid } } + }; + ContentstackResponse response = await _stack.Taxonomy().UnpublishAsync(model); + if (response.StatusCode == System.Net.HttpStatusCode.Forbidden) + { + AssertLogger.Inconclusive("taxonomy_publish feature not enabled on this stack; skipping."); + return; + } + AssertLogger.IsTrue(response.IsSuccessStatusCode, $"UnpublishAsync failed: {response.OpenResponse()}", "UnpublishTaxonomyAsyncSuccess"); + } + + [TestMethod] + public void Test284_Should_Unlocalize_Taxonomy() + { + TestOutputLogger.LogContext("TestScenario", "Test284_Should_Unlocalize_Taxonomy"); + if (string.IsNullOrEmpty(_testLocaleCode)) + { + AssertLogger.Inconclusive("No non-master locale available; skipping taxonomy unlocalize test."); + return; + } + + // Ensure the taxonomy is localized first so unlocalize has something to remove. + var localizeModel = new TaxonomyModel { Name = "Taxonomy For Unlocalize" }; + var localizeColl = new ParameterCollection(); + localizeColl.Add("locale", _testLocaleCode); + _stack.Taxonomy(_taxonomyUid).Localize(localizeModel, localizeColl); + + ContentstackResponse response = _stack.Taxonomy(_taxonomyUid).Unlocalize(_testLocaleCode); + AssertLogger.IsTrue(response.IsSuccessStatusCode, $"Unlocalize failed: {response.OpenResponse()}", "UnlocalizeTaxonomySuccess"); + } + + [TestMethod] + public async Task Test285_Should_Unlocalize_Taxonomy_Async() + { + TestOutputLogger.LogContext("TestScenario", "Test285_Should_Unlocalize_Taxonomy_Async"); + if (string.IsNullOrEmpty(_asyncTestLocaleCode)) + { + AssertLogger.Inconclusive("No second non-master locale available; skipping async unlocalize test."); + return; + } + + var localizeModel = new TaxonomyModel { Name = "Taxonomy For Unlocalize Async" }; + var localizeColl = new ParameterCollection(); + localizeColl.Add("locale", _asyncTestLocaleCode); + await _stack.Taxonomy(_taxonomyUid).LocalizeAsync(localizeModel, localizeColl); + + ContentstackResponse response = await _stack.Taxonomy(_taxonomyUid).UnlocalizeAsync(_asyncTestLocaleCode); + AssertLogger.IsTrue(response.IsSuccessStatusCode, $"UnlocalizeAsync failed: {response.OpenResponse()}", "UnlocalizeTaxonomyAsyncSuccess"); + } + + [TestMethod] + public void Test286_Should_Unlocalize_Term() + { + TestOutputLogger.LogContext("TestScenario", "Test286_Should_Unlocalize_Term"); + if (string.IsNullOrEmpty(_testLocaleCode) || string.IsNullOrEmpty(_rootTermUid)) + { + AssertLogger.Inconclusive("No non-master locale or root term available; skipping term unlocalize test."); + return; + } + + // Localize the term first so unlocalize has something to remove. + var localizeModel = new TermModel { Name = "Root Term For Unlocalize" }; + var localizeColl = new ParameterCollection(); + localizeColl.Add("locale", _testLocaleCode); + _stack.Taxonomy(_taxonomyUid).Terms(_rootTermUid).Localize(localizeModel, localizeColl); + + ContentstackResponse response = _stack.Taxonomy(_taxonomyUid).Terms(_rootTermUid).Unlocalize(_testLocaleCode); + AssertLogger.IsTrue(response.IsSuccessStatusCode, $"Term Unlocalize failed: {response.OpenResponse()}", "UnlocalizeTermSuccess"); + } + + [TestMethod] + public async Task Test287_Should_Unlocalize_Term_Async() + { + TestOutputLogger.LogContext("TestScenario", "Test287_Should_Unlocalize_Term_Async"); + if (string.IsNullOrEmpty(_asyncTestLocaleCode) || string.IsNullOrEmpty(_rootTermUid)) + { + AssertLogger.Inconclusive("No second non-master locale or root term available; skipping async term unlocalize test."); + return; + } + + var localizeModel = new TermModel { Name = "Root Term For Unlocalize Async" }; + var localizeColl = new ParameterCollection(); + localizeColl.Add("locale", _asyncTestLocaleCode); + await _stack.Taxonomy(_taxonomyUid).Terms(_rootTermUid).LocalizeAsync(localizeModel, localizeColl); + + ContentstackResponse response = await _stack.Taxonomy(_taxonomyUid).Terms(_rootTermUid).UnlocalizeAsync(_asyncTestLocaleCode); + AssertLogger.IsTrue(response.IsSuccessStatusCode, $"Term UnlocalizeAsync failed: {response.OpenResponse()}", "UnlocalizeTermAsyncSuccess"); + } + + [TestMethod] + public void Test288_Should_Throw_When_Publish_With_Uid_Set() + { + TestOutputLogger.LogContext("TestScenario", "Test288_Should_Throw_When_Publish_With_Uid_Set"); + var model = new TaxonomyPublishModel + { + Locales = new List { "en-us" }, + Environments = new List { "development" }, + Items = new List { new TaxonomyPublishItem { Uid = _taxonomyUid } } + }; + AssertLogger.ThrowsException( + () => _stack.Taxonomy(_taxonomyUid).Publish(model), "PublishWithUidSet"); + } + + [TestMethod] + public void Test289_Should_Throw_When_Unlocalize_Without_Uid() + { + TestOutputLogger.LogContext("TestScenario", "Test289_Should_Throw_When_Unlocalize_Without_Uid"); + AssertLogger.ThrowsException( + () => _stack.Taxonomy().Unlocalize("en-us"), "UnlocalizeWithoutUid"); + } + private static Stack GetStack() { StackResponse response = StackResponse.getStack(_client.serializer);