From d5b420dc524f15df38d02a89ba861937f769ffb3 Mon Sep 17 00:00:00 2001 From: mammabear123 <127075115+mammabear123@users.noreply.github.com> Date: Fri, 22 Dec 2023 16:26:21 +0800 Subject: [PATCH] NotFor matches should still depend on Target Field name. --- .../RevisionUtils/FieldMapperUtils.cs | 11 +- .../JiraValueMapperTests.cs | 280 ++++++++++++++++++ 2 files changed, 286 insertions(+), 5 deletions(-) create mode 100644 src/WorkItemMigrator/tests/Migration.Jira-Export.Tests/JiraValueMapperTests.cs diff --git a/src/WorkItemMigrator/JiraExport/RevisionUtils/FieldMapperUtils.cs b/src/WorkItemMigrator/JiraExport/RevisionUtils/FieldMapperUtils.cs index 4de29ddb..c9f932c2 100644 --- a/src/WorkItemMigrator/JiraExport/RevisionUtils/FieldMapperUtils.cs +++ b/src/WorkItemMigrator/JiraExport/RevisionUtils/FieldMapperUtils.cs @@ -70,11 +70,13 @@ public static (bool, object) MapValue(JiraRevision r, string itemSource, string if (!hasFieldValue) return (false, null); - foreach (var item in config.FieldMap.Fields) + foreach (var item in config.FieldMap.Fields.Where(i => i.Mapping?.Values != null)) { - if ((((item.Source == itemSource && item.Target == itemTarget) && (item.For.Contains(targetWit) || item.For == "All")) || - item.Source == itemSource && (!string.IsNullOrWhiteSpace(item.NotFor) && !item.NotFor.Contains(targetWit))) && - item.Mapping?.Values != null) + var sourceAndTargetMatch = item.Source == itemSource && item.Target == itemTarget; + var forOrAllMatch = item.For.Contains(targetWit) || item.For == "All"; // matches "For": "All", or when this Wit is specifically named. + var notForMatch = !string.IsNullOrWhiteSpace(item.NotFor) && !item.NotFor.Contains(targetWit); // matches if not-for is specified and doesn't contain this Wit. + + if (sourceAndTargetMatch && (forOrAllMatch || notForMatch)) { if (value == null) { @@ -89,7 +91,6 @@ public static (bool, object) MapValue(JiraRevision r, string itemSource, string } } return (true, value); - } public static (bool, object) MapRenderedValue(JiraRevision r, string sourceField, bool isCustomField, string customFieldName, ConfigJson config) diff --git a/src/WorkItemMigrator/tests/Migration.Jira-Export.Tests/JiraValueMapperTests.cs b/src/WorkItemMigrator/tests/Migration.Jira-Export.Tests/JiraValueMapperTests.cs new file mode 100644 index 00000000..8a10a274 --- /dev/null +++ b/src/WorkItemMigrator/tests/Migration.Jira-Export.Tests/JiraValueMapperTests.cs @@ -0,0 +1,280 @@ +using NUnit.Framework; +using NSubstitute; +using AutoFixture; +using Common.Config; +using JiraExport; +using Migration.Common.Config; +using System.Collections.Generic; +using System; +using Newtonsoft.Json.Linq; +using Type = Migration.Common.Config.Type; +using AutoFixture.AutoNSubstitute; + +namespace Migration.Jira_Export.Tests +{ + + [TestFixture] + public class JiraValueMapperTests + { + // use auto fixture to help mock and instantiate with dummy data with nsubsitute. + private Fixture _fixture; + private ConfigJson _config; + private JiraItem _item; + private IJiraProvider _provider; + + [SetUp] + public void SetupValueMapperTests() + { + _fixture = new Fixture(); + _fixture.Customize(new AutoNSubstituteCustomization() { }); + _fixture.Behaviors.Add(new OmitOnRecursionBehavior()); + + _config = new ConfigJson + { + TypeMap = new TypeMap + { + Types = new List + { + new Type { Source = "Bug", Target = "Defect" }, + new Type { Source = "Task", Target = "Work Item" } + } + }, + FieldMap = new FieldMap + { + Fields = new List + { + new Field + { + Source = "Priority", + Target = "Severity", + For = "All", + Mapping = new Mapping + { + Values = new List + { + new Value { Source = "High", Target = "Critical" }, + new Value { Source = "Medium", Target = "Major" }, + new Value { Source = "Low", Target = "Minor" } + } + } + }, + new Field + { + Source = "Status", + Target = "State", + For = "Defect", + Mapping = new Mapping + { + Values = new List + { + new Value { Source = "Open", Target = "Active" }, + new Value { Source = "In Progress", Target = "In Development" }, + new Value { Source = "Resolved", Target = "Fixed" }, + new Value { Source = "Closed", Target = "Closed" } + } + } + }, + new Field + { + Source = "Empty", + Target = "Mapping", + Mapping = null + } + } + } + }; + + _provider = CreateJiraProvider(); + string issueKey = "issue_key"; + _item = JiraItem.CreateFromRest(issueKey, _provider); + } + + [Test] + public void MapValue_WithNullRevision_ThrowsArgumentNullException() + { + // Arrange + JiraRevision revision = null; + string itemSource = "Priority"; + string itemTarget = "Severity"; + + // Act & Assert + Assert.Throws(() => FieldMapperUtils.MapValue(revision, itemSource, itemTarget, _config)); + } + + [Test] + public void MapValue_WithNullConfig_ThrowsArgumentNullException() + { + // Arrange + ConfigJson config = null; + string itemSource = "Priority"; + string itemTarget = "Severity"; + var revision = new JiraRevision(_item) + { + Fields = new Dictionary + { + { "Priority", "High" }, + { "Status", "Open" } + } + }; + + // Act & Assert + Assert.Throws(() => FieldMapperUtils.MapValue(revision, itemSource, itemTarget, config)); + } + + [Test] + public void MapValue_WithNonExistingField_ReturnsFalseAndNull() + { + // Arrange + string itemSource = "NonExistingField"; + string itemTarget = "Severity"; + var revision = new JiraRevision(_item) + { + Fields = new Dictionary + { + { "Priority", "High" }, + { "Status", "Open" } + } + }; + + // Act + var result = FieldMapperUtils.MapValue(revision, itemSource, itemTarget, _config); + + // Assert + Assert.IsFalse(result.Item1); + Assert.IsNull(result.Item2); + } + + [Test] + public void MapValue_WithExistingFieldAndMapping_ReturnsTrueAndMappedValue() + { + // Arrange + string itemSource = "Priority"; + string itemTarget = "Severity"; + var revision = new JiraRevision(_item) + { + Fields = new Dictionary + { + { "Priority", "High" }, + { "Status", "Open" } + } + }; + + // Act + var result = FieldMapperUtils.MapValue(revision, itemSource, itemTarget, _config); + + // Assert + Assert.IsTrue(result.Item1); + Assert.AreEqual("Critical", result.Item2); + } + + [Test] + public void MapValue_WithMatchesNotForButTargetDoesNotMatch_ReturnsFalseAndNull() + { + // Arrange + string itemSource = "Status"; + string itemTarget = "target"; + var revision = new JiraRevision(_item) // type is Bug by default; + { + Fields = new Dictionary + { + { "Status", "Open" }, + { "SomethingElse", "SomethingElse" } + } + }; + var typeMap = new TypeMap + { + Types = new List + { + new Type { Source = "Bug", Target = "Bug" }, + new Type { Source = "Task", Target = "Work Item" } + } + }; + var fieldConfig = new Field + { + Source = "Status", + Target = "XXXNotStateXXX", + NotFor = "Defect", + Mapping = new Mapping + { + Values = new List + { + new Value { Source = "Open", Target = "Active" }, + new Value { Source = "In Progress", Target = "In Development" }, + new Value { Source = "Resolved", Target = "Fixed" }, + new Value { Source = "Closed", Target = "Closed" } + } + } + }; + + var config = new ConfigJson(); + config.FieldMap = new FieldMap(); + config.FieldMap.Fields = new List { fieldConfig }; + config.TypeMap = typeMap; + + // Act + var result = FieldMapperUtils.MapValue(revision, itemSource, itemTarget, config); + + // Assert + Assert.IsTrue(result.Item1); + Assert.AreNotEqual("Active", result.Item2); + Assert.AreEqual("Open", result.Item2); // no mapping should have taken place + + } + + [Test] + public void MapValue_WithExistingFieldAndNoMapping_ReturnsTrueAndOriginalValue() + { + // Arrange + string itemSource = "FieldWithNoMapping"; + string itemTarget = "Target"; + var revision = new JiraRevision(_item) + { + Fields = new Dictionary + { + { "Priority", "High" }, + { "Status", "Open" }, + { "FieldWithNoMapping", "SourceValue" } + } + }; + + // Act + var result = FieldMapperUtils.MapValue(revision, itemSource, itemTarget, _config); + + // Assert + Assert.IsTrue(result.Item1); + Assert.AreEqual("SourceValue", result.Item2); + } + + private JiraSettings CreateJiraSettings() + { + JiraSettings settings = new JiraSettings("userID", "pass", "token", "url", "project"); + settings.EpicLinkField = "Epic Link"; + settings.SprintField = "SprintField"; + + return settings; + } + + private IJiraProvider CreateJiraProvider(JObject remoteIssue = null) + { + IJiraProvider provider = Substitute.For(); + provider.GetSettings().ReturnsForAnyArgs(CreateJiraSettings()); + provider.DownloadIssue(default).ReturnsForAnyArgs(remoteIssue ?? CreateRemoteIssueJObject()); + + return provider; + } + + private JObject CreateRemoteIssueJObject(string workItemType = "Bug", string issueKey = "issue_key") + { + var issueType = JObject.Parse("{ 'issuetype': {'name': '"+ workItemType +"'}}"); + var renderedFields = JObject.Parse("{ 'custom_field_name': 'SomeValue', 'description': 'RenderedDescription' }"); + + return new JObject + { + { "fields", issueType }, + { "renderedFields", renderedFields }, + { "key", issueKey } + }; + + } + } +} \ No newline at end of file