diff --git a/.github/workflows/CodeQuality.yml b/.github/workflows/CodeQuality.yml index d0899b4..642a5cf 100644 --- a/.github/workflows/CodeQuality.yml +++ b/.github/workflows/CodeQuality.yml @@ -33,6 +33,9 @@ jobs: - name: add DevExpress nuget feed run: dotnet nuget add source https://nuget.devexpress.com/api -n DXFeed -u DevExpress -p ${{ secrets.DEVEXPRESS_NUGET_KEY }} --store-password-in-clear-text + - name: Setup DotCover + run: dotnet tool install --global JetBrains.dotCover.GlobalTool + - name: Restore dependencies run: nuget restore ea-modelkit.sln @@ -41,13 +44,13 @@ jobs: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} run: | dotnet tool install --global dotnet-sonarscanner - dotnet sonarscanner begin /k:"STARIONGROUP_ea-modelkit" /o:"stariongroup" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.opencover.reportsPaths="./CoverageResults/coverage.opencover.xml" + dotnet sonarscanner begin /k:"STARIONGROUP_ea-modelkit" /o:"stariongroup" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.cs.dotcover.reportsPaths=dotCover.Output.html - name: Build run: msbuild ea-modelkit.sln -property:Configuration=CICD -property:platform="Any CPU" /p:RestorePackages=false - name: Run Tests and Compute Coverage - run: vstest.console.exe EA-ModelKit.Tests\bin\CICD\net481\EAModelKit.Tests.dll /Platform:x64 /EnableCodeCoverage + run: dotnet dotcover test --dcReportType=HTML -c CICD --dcAttributeFilters=System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute - name: Sonarqube end run: dotnet sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}" \ No newline at end of file diff --git a/EA-ModelKit.Tests/EA-ModelKit.Tests.csproj b/EA-ModelKit.Tests/EA-ModelKit.Tests.csproj index 35fc987..60c981d 100644 --- a/EA-ModelKit.Tests/EA-ModelKit.Tests.csproj +++ b/EA-ModelKit.Tests/EA-ModelKit.Tests.csproj @@ -11,11 +11,11 @@ - - - - - + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -23,17 +23,25 @@ - + - + + ..\lib\Interop.EA.dll + - - ..\lib\Interop.EA.dll - + + Always + + + Always + + + Always + \ No newline at end of file diff --git a/EA-ModelKit.Tests/Extensions/ContainerBuilderExtensionsTestFixture.cs b/EA-ModelKit.Tests/Extensions/ContainerBuilderExtensionsTestFixture.cs new file mode 100644 index 0000000..108b125 --- /dev/null +++ b/EA-ModelKit.Tests/Extensions/ContainerBuilderExtensionsTestFixture.cs @@ -0,0 +1,51 @@ +// ------------------------------------------------------------------------------------------------- +// +// +// Copyright (C) 2024 Starion Group S.A. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +// ----------------------------------------------------------------------------------------------- + +namespace EAModelKit.Tests.Extensions +{ + using Autofac; + + using EAModelKit.Extensions; + + using NUnit.Framework; + + [TestFixture] + public class ContainerBuilderExtensionsTestFixture + { + private ContainerBuilder containerBuilder; + + [SetUp] + public void SetUp() + { + this.containerBuilder = new ContainerBuilder(); + } + + [Test] + public void VerifyContainerBuilderExtensions() + { + Assert.Multiple(() => + { + Assert.That(() => this.containerBuilder.RegisterViewModels(), Throws.Nothing); + Assert.That(() => this.containerBuilder.RegisterServices(), Throws.Nothing); + Assert.That(() => this.containerBuilder.Build(), Throws.Nothing); + }); + } + } +} diff --git a/EA-ModelKit.Tests/Helpers/TestCollection.cs b/EA-ModelKit.Tests/Helpers/TestCollection.cs new file mode 100644 index 0000000..304d894 --- /dev/null +++ b/EA-ModelKit.Tests/Helpers/TestCollection.cs @@ -0,0 +1,192 @@ +// ------------------------------------------------------------------------------------------------- +// +// +// Copyright (C) 2024 Starion Group S.A. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +// ----------------------------------------------------------------------------------------------- + +namespace EAModelKit.Tests.Helpers +{ + using System.Collections; + using System.Diagnostics.CodeAnalysis; + + using EA; + + using Moq; + + /// + /// Class that is there to facilitate unit tests when touching , since all constructors for all EA classes are internal + /// + [ExcludeFromCodeCoverage] + public class TestCollection : Collection + { + /// + /// A containedObjects of the contained object + /// + private readonly List containedObjects; + + /// + /// Initializes a new instance of the class. + /// + public TestCollection() + { + this.containedObjects = []; + } + + /// + /// Initializes a new instance of the class. + /// + /// A collection of + public TestCollection(IEnumerable objects) + { + this.containedObjects = objects.ToList(); + } + + /// + /// Gets the number of contained objects + /// + public short Count => (short)this.containedObjects.Count; + + /// + /// Gets the of contained objects + /// + public ObjectType ObjectType => 0; + + /// + /// Retrieves a contained object at the given index + /// + /// The index of the object + /// The contained object + public object GetAt(short index) + { + return this.IsIndexInRange(index) ? this.containedObjects[index] : null; + } + + /// + /// Removes a contained object + /// + /// The index of the object + /// Not used + public void DeleteAt(short index, bool refresh) + { + if (!this.IsIndexInRange(index)) + { + return; + } + + this.containedObjects.RemoveAt(index); + } + + /// + /// Gets the last occured error (Not used) + /// + /// null + public string GetLastError() + { + return null; + } + + /// + /// Gets a object by his name (Not used) + /// + /// The name of the object + /// null + public object GetByName(string name) + { + foreach (var containedObject in this.containedObjects) + { + if (containedObject is TaggedValue taggedValue && taggedValue.Name == name) + { + return taggedValue; + } + } + + return null; + } + + /// + /// Refresh the collection (Not used) + /// + public void Refresh() + { + } + + /// + /// Adds a new object to the contained objects + /// + /// The name of the object + /// The Type if the object + /// The created object + public object AddNew(string Name, string Type) + { + if (Type == nameof(TaggedValue)) + { + var newTaggedValue = new Mock(); + newTaggedValue.Setup(x => x.Name).Returns(Name); + this.Add(newTaggedValue.Object); + return newTaggedValue.Object; + } + + return null; + } + + /// + /// Removes a contained object + /// + /// The index of the objects to removed + public void Delete(short index) + { + this.DeleteAt(index, false); + } + + /// + /// Gets the to iterate through the collection + /// + /// The + public IEnumerator GetEnumerator() + { + return this.containedObjects.GetEnumerator(); + } + + /// + /// Adds an object to the contained Object + /// + /// The new object + public void Add(object newObject) + { + this.containedObjects.Add(newObject); + } + + /// + /// Adds a collection of object + /// + /// The collection to add + public void AddRange(IEnumerable objects) + { + this.containedObjects.AddRange(objects); + } + + /// + /// Asserts if the given index is in range of the collection + /// + /// The index + /// Asserts that the index is in range + private bool IsIndexInRange(short index) + { + return index >= 0 && index < this.containedObjects.Count; + } + } +} diff --git a/EA-ModelKit.Tests/Resources/SelectionService/AllExistingPackages.xml b/EA-ModelKit.Tests/Resources/SelectionService/AllExistingPackages.xml new file mode 100644 index 0000000..37f6c8b --- /dev/null +++ b/EA-ModelKit.Tests/Resources/SelectionService/AllExistingPackages.xml @@ -0,0 +1,259 @@ + + + + + + 1 + 0 + + + 2 + 1 + + + 3 + 2 + + + 4 + 2 + + + 5 + 2 + + + 6 + 2 + + + 7 + 2 + + + 8 + 2 + + + 9 + 2 + + + 18 + 2 + + + 54 + 2 + + + 57 + 2 + + + 78 + 2 + + + 10 + 3 + + + 12 + 3 + + + 13 + 3 + + + 15 + 3 + + + 17 + 4 + + + 19 + 5 + + + 29 + 5 + + + 34 + 5 + + + 40 + 5 + + + 37 + 6 + + + 51 + 6 + + + 53 + 6 + + + 93 + 7 + + + 11 + 8 + + + 27 + 8 + + + 42 + 9 + + + 43 + 9 + + + 70 + 9 + + + 97 + 9 + + + 16 + 15 + + + 20 + 19 + + + 21 + 19 + + + 22 + 19 + + + 50 + 27 + + + 52 + 37 + + + 110 + 43 + + + 111 + 43 + + + 112 + 43 + + + 94 + 57 + + + 95 + 57 + + + 100 + 70 + + + 101 + 70 + + + 102 + 70 + + + 104 + 70 + + + 105 + 70 + + + 83 + 80 + + + 89 + 81 + + + 90 + 81 + + + 85 + 82 + + + 84 + 83 + + + 88 + 83 + + + 91 + 83 + + + 92 + 83 + + + 86 + 85 + + + 87 + 85 + + + 80 + 93 + + + 81 + 93 + + + 82 + 93 + + + 106 + 110 + + + 107 + 111 + + + + diff --git a/EA-ModelKit.Tests/Resources/SelectionService/AllSelectedElements.xml b/EA-ModelKit.Tests/Resources/SelectionService/AllSelectedElements.xml new file mode 100644 index 0000000..d5013b5 --- /dev/null +++ b/EA-ModelKit.Tests/Resources/SelectionService/AllSelectedElements.xml @@ -0,0 +1,34 @@ + + + + + + 20 + + + 25 + + + 26 + + + 10 + + + 27 + + + 28 + + + 1605 + + + 1607 + + + 1608 + + + + diff --git a/EA-ModelKit.Tests/Resources/SelectionService/EmptyElements.xml b/EA-ModelKit.Tests/Resources/SelectionService/EmptyElements.xml new file mode 100644 index 0000000..77a2d7a --- /dev/null +++ b/EA-ModelKit.Tests/Resources/SelectionService/EmptyElements.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/EA-ModelKit.Tests/Services/Dispatcher/DispatcherServiceTestFixture.cs b/EA-ModelKit.Tests/Services/Dispatcher/DispatcherServiceTestFixture.cs new file mode 100644 index 0000000..c813c8e --- /dev/null +++ b/EA-ModelKit.Tests/Services/Dispatcher/DispatcherServiceTestFixture.cs @@ -0,0 +1,103 @@ +// ------------------------------------------------------------------------------------------------- +// +// +// Copyright (C) 2024 Starion Group S.A. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +// ----------------------------------------------------------------------------------------------- + +namespace EAModelKit.Tests.Services.Dispatcher +{ + using EA; + + using EAModelKit.Services.Dispatcher; + using EAModelKit.Services.Logger; + using EAModelKit.Services.Selection; + + using Microsoft.Extensions.Logging; + + using Moq; + + using NUnit.Framework; + + [TestFixture] + public class DispatcherServiceTestFixture + { + private DispatcherService dispatcher; + private Mock selectionService; + private Mock loggerService; + private Mock repository; + + [SetUp] + public void Setup() + { + this.selectionService = new Mock(); + this.loggerService = new Mock(); + this.repository = new Mock(); + + this.dispatcher = new DispatcherService(this.loggerService.Object, this.selectionService.Object); + } + + [Test] + public void VerifyConnect() + { + this.dispatcher.Connect(this.repository.Object); + + Assert.Multiple(() => + { + this.loggerService.Verify(x => x.InitializeService(this.repository.Object), Times.Once); + this.loggerService.Verify(x => x.Log(LogLevel.Information, "EA Model-Kit plugin successfully connected to EA"), Times.Once); + }); + } + + [Test] + public void VerifyDisconnect() + { + this.dispatcher.Disconnect(); + this.loggerService.Verify(x => x.Log(LogLevel.Information, "EA Model-Kit plugin successfully disconnected to EA"), Times.Once); + } + + [Test] + public void VerifyOnGenericExport() + { + var selectedElements = new List + { + CreateNewElement("Requirement"), + CreateNewElement("Requirement"), + CreateNewElement("Requirement"), + CreateNewElement("Requirement"), + CreateNewElement("Block"), + CreateNewElement("Block"), + CreateNewElement("Block") + }; + + this.selectionService.Setup(x => x.QuerySelectedElements(this.repository.Object)).Returns(selectedElements); + this.dispatcher.OnGenericExport(this.repository.Object); + + Assert.Multiple(() => + { + this.loggerService.Verify(x => x.Log(LogLevel.Debug, "Found {0} Elements With Stereotype {1}", 4, "Requirement"), Times.Once); + this.loggerService.Verify(x => x.Log(LogLevel.Debug, "Found {0} Elements With Stereotype {1}", 3, "Block"), Times.Once); + }); + } + + private static Element CreateNewElement(string stereotypeName) + { + var element = new Mock(); + element.Setup(x => x.Stereotype).Returns(stereotypeName); + return element.Object; + } + } +} diff --git a/EA-ModelKit.Tests/Services/Logger/LoggerServiceTestFixture.cs b/EA-ModelKit.Tests/Services/Logger/LoggerServiceTestFixture.cs index 4be533a..b15f60f 100644 --- a/EA-ModelKit.Tests/Services/Logger/LoggerServiceTestFixture.cs +++ b/EA-ModelKit.Tests/Services/Logger/LoggerServiceTestFixture.cs @@ -1,7 +1,7 @@ // ------------------------------------------------------------------------------------------------- -// +// // -// Copyright 2024 Starion Group S.A. +// Copyright (C) 2024 Starion Group S.A. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -9,14 +9,14 @@ // // http://www.apache.org/licenses/LICENSE-2.0 // -// Unless required by applicable law or agreed to in writing, softwareUseCases +// Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // -// -// ------------------------------------------------------------------------------------------------ +// +// ----------------------------------------------------------------------------------------------- namespace EAModelKit.Tests.Services.Logger { diff --git a/EA-ModelKit.Tests/Services/SelectionService/SelectionServiceTestFixture.cs b/EA-ModelKit.Tests/Services/SelectionService/SelectionServiceTestFixture.cs new file mode 100644 index 0000000..05e793c --- /dev/null +++ b/EA-ModelKit.Tests/Services/SelectionService/SelectionServiceTestFixture.cs @@ -0,0 +1,129 @@ +// ------------------------------------------------------------------------------------------------- +// +// +// Copyright (C) 2024 Starion Group S.A. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +// ----------------------------------------------------------------------------------------------- + +namespace EAModelKit.Tests.Services.SelectionService +{ + using System.Xml.Linq; + + using EA; + + using EAModelKit.Services.Selection; + using EAModelKit.Tests.Helpers; + + using Moq; + + using NUnit.Framework; + + using File = System.IO.File; + + [TestFixture] + public class SelectionServiceTestFixture + { + private SelectionService selectionService; + private Mock repository; + private Mock selection; + + [SetUp] + public void Setup() + { + this.repository = new Mock(); + this.selectionService = new SelectionService(); + this.selection = new Mock(); + this.repository.Setup(x => x.CurrentSelection).Returns(this.selection.Object); + } + + [Test] + public void VerifyQuerySelectedElementsNoPackage() + { + this.selection.Setup(x => x.List).Returns(new TestCollection()); + this.selection.Setup(x => x.ElementSet).Returns(new TestCollection()); + + Assert.That(this.selectionService.QuerySelectedElements(this.repository.Object), Is.Empty); + + // Contains 4 Elements and 3 Diagrams + var selectedElements = new List + { + new Mock().Object, + new Mock().Object, + new Mock().Object, + new Mock().Object, + new Mock().Object, + new Mock().Object, + new Mock().Object + }; + + this.selection.Setup(x => x.ElementSet).Returns(new TestCollection(selectedElements)); + var selectedElementsResponse = this.selectionService.QuerySelectedElements(this.repository.Object); + + Assert.Multiple(() => + { + Assert.That(selectedElementsResponse, Is.Not.Empty); + Assert.That(selectedElementsResponse, Has.Count.EqualTo(4)); + Assert.That(selectedElementsResponse, Is.All.AssignableTo(typeof(Element))); + }); + } + + [Test] + public void VerifyQuerySelectedElements() + { + var rootPackage = new Mock(); + rootPackage.Setup(x => x.BaseType).Returns(nameof(Package)); + rootPackage.Setup(x => x.ElementID).Returns(1); + + this.selection.Setup(x => x.List).Returns(new TestCollection([rootPackage.Object])); + var existingPackagesContent = QueryResourceContent("AllExistingPackages.xml"); + this.repository.Setup(x => x.SQLQuery(It.Is(s => s.Contains(" from t_package ")))).Returns(existingPackagesContent); + + var emptyElementsContent = QueryResourceContent("EmptyElements.xml"); + this.repository.Setup(x => x.SQLQuery(It.Is(s => s.Contains(" from t_object ")))).Returns(emptyElementsContent); + + Assert.That(this.selectionService.QuerySelectedElements(this.repository.Object), Is.Empty); + + // Contains 9 ids + var existingElementsContent = QueryResourceContent("AllSelectedElements.xml"); + this.repository.Setup(x => x.SQLQuery(It.Is(s => s.Contains(" from t_object ")))).Returns(existingElementsContent); + + var existingElements = new List(); + var xElement = XElement.Parse(existingElementsContent); + + for (var existingElementsIndex = 0; existingElementsIndex < xElement.Descendants("Row").Count(); existingElementsIndex++) + { + existingElements.Add(new Mock().Object); + } + + this.repository.Setup(x => x.GetElementSet(It.IsAny(), 0)).Returns(new TestCollection(existingElements)); + + var selectedElementsResponse = this.selectionService.QuerySelectedElements(this.repository.Object); + + Assert.Multiple(() => + { + Assert.That(selectedElementsResponse, Is.Not.Empty); + Assert.That(selectedElementsResponse, Has.Count.EqualTo(9)); + Assert.That(selectedElementsResponse, Is.All.AssignableTo(typeof(Element))); + }); + } + + private static string QueryResourceContent(string fileName) + { + var path = Path.Combine(Directory.GetCurrentDirectory(), "Resources", "SelectionService", fileName); + return File.ReadAllText(path); + } + } +} diff --git a/EA-ModelKit.sln.DotSettings b/EA-ModelKit.sln.DotSettings index b5f4015..f993bb2 100644 --- a/EA-ModelKit.sln.DotSettings +++ b/EA-ModelKit.sln.DotSettings @@ -277,10 +277,10 @@ True False False - ------------------------------------------------------------------------------------------------- - <copyright file="${File.FileName}" company="Starion Group S.A."> + ------------------------------------------------------------------------------------------------- +<copyright file="${File.FileName}" company="Starion Group S.A."> - Copyright ${CurrentDate.Year} Starion Group S.A. + Copyright (C) ${CurrentDate.Year} Starion Group S.A. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -288,14 +288,14 @@ http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, softwareUseCases + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - </copyright> - ------------------------------------------------------------------------------------------------ +</copyright> +----------------------------------------------------------------------------------------------- True False <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> diff --git a/EA-ModelKit/App.cs b/EA-ModelKit/App.cs index be4a6dc..43d7792 100644 --- a/EA-ModelKit/App.cs +++ b/EA-ModelKit/App.cs @@ -1,7 +1,7 @@ // ------------------------------------------------------------------------------------------------- -// +// // -// Copyright 2024 Starion Group S.A. +// Copyright (C) 2024 Starion Group S.A. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -9,14 +9,14 @@ // // http://www.apache.org/licenses/LICENSE-2.0 // -// Unless required by applicable law or agreed to in writing, softwareUseCases +// Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // -// -// ------------------------------------------------------------------------------------------------ +// +// ----------------------------------------------------------------------------------------------- namespace EAModelKit { @@ -32,6 +32,7 @@ namespace EAModelKit using EA; using EAModelKit.Extensions; + using EAModelKit.Services.Dispatcher; using EAModelKit.Services.Logger; using EAModelKit.Services.Version; @@ -48,16 +49,6 @@ namespace EAModelKit [ExcludeFromCodeCoverage] public class App { - /// - /// Gets the - /// - private ILoggerService logger; - - /// - /// Gets the - /// - private IVersionService versionService; - /// /// The name of the Ribbon Category /// @@ -67,12 +58,27 @@ public class App /// The name of the menu header, inisde the ribbon /// private const string MenuHeaderName = "-&EA ModelKit"; - + /// /// The name of the Generic Export Entry /// private const string GenericExportEntry = "&Generic Export"; + /// + /// Gets the + /// + private IDispatcherService dispatcher; + + /// + /// Gets the + /// + private ILoggerService logger; + + /// + /// Gets the + /// + private IVersionService versionService; + /// /// Initializes a new instance of the class. /// @@ -106,7 +112,7 @@ public App() Log.Logger.Write(LogEventLevel.Fatal, ex, "App failed to start"); } } - + /// /// Gets or sets the /// @@ -121,23 +127,25 @@ public static void BuildContainer(ContainerBuilder containerBuilder = null) containerBuilder ??= new ContainerBuilder(); Container = containerBuilder.Build(); } - + /// /// Called before EA starts to check Add-In Exists, necessary for the Add-In to work /// /// The public void EA_Connect(Repository repository) { + this.dispatcher.Connect(repository); } - + /// /// EA calls this operation on Exit /// public void EA_Disconnect() { + this.dispatcher.Disconnect(); AppDomain.CurrentDomain.AssemblyResolve -= CurrentDomainOnAssemblyResolve; } - + /// /// Used by EA to identify the the Ribbon in which the Add-In should place its menu icon /// @@ -147,7 +155,7 @@ public string EA_GetRibbonCategory(Repository _) { return RibbonCategoryName; } - + /// /// Called when user Clicks Add-Ins Menu item from within EA. /// @@ -183,6 +191,44 @@ public object EA_GetMenuItems(Repository repository, string location, string men return null; } + /// + /// EA_MenuClick events are received by an Add-In in response to user selection of a menu option. + /// The event is raised when the user clicks on a particular menu option. When a user clicks on one of your non-parent menu + /// options, your Add-In receives a MenuClick event. + /// Notice that your code can directly access Enterprise Architect data and UI elements using CurrentRepository methods. + /// + /// + /// An EA.CurrentRepository object representing the currently open Enterprise Architect model. Poll its + /// members to retrieve model data and user interface status information. + /// + /// Not used + /// + /// The name of the parent menu for which sub-items are to be defined. + /// In the case of the top-level menu this is an empty string. + /// Not used. + /// + /// The name of the option actually clicked. + public void EA_MenuClick(Repository repository, string location, string menuName, string itemName) + { + try + { + switch (itemName) + { + case GenericExportEntry: + this.dispatcher.OnGenericExport(repository); + break; + default: + this.logger.Log(LogLevel.Error, "Unsupported item action {0}", itemName); + break; + } + } + catch (Exception ex) + { + this.logger.LogException(ex, "An exception occured while proceeding to the {0} action!", itemName); + throw; + } + } + /// /// Called once Menu has been opened to see what menu items should active. /// @@ -207,8 +253,9 @@ private void ResolveRequiredServices() loggerFactory.AddSerilog(); this.logger = scope.Resolve(); this.versionService = scope.Resolve(); + this.dispatcher = scope.Resolve(); } - + /// /// Occures when event is called /// diff --git a/EA-ModelKit/EA-ModelKit.csproj b/EA-ModelKit/EA-ModelKit.csproj index e8ec223..d19c08e 100644 --- a/EA-ModelKit/EA-ModelKit.csproj +++ b/EA-ModelKit/EA-ModelKit.csproj @@ -31,20 +31,20 @@ - - - - - - - - - + + + + + + + + + ..\lib\Interop.EA.dll - + \ No newline at end of file diff --git a/EA-ModelKit/Extensions/ContainerBuilderExtensions.cs b/EA-ModelKit/Extensions/ContainerBuilderExtensions.cs index 6201b51..fc3f513 100644 --- a/EA-ModelKit/Extensions/ContainerBuilderExtensions.cs +++ b/EA-ModelKit/Extensions/ContainerBuilderExtensions.cs @@ -1,7 +1,7 @@ // ------------------------------------------------------------------------------------------------- -// +// // -// Copyright 2024 Starion Group S.A. +// Copyright (C) 2024 Starion Group S.A. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -9,14 +9,14 @@ // // http://www.apache.org/licenses/LICENSE-2.0 // -// Unless required by applicable law or agreed to in writing, softwareUseCases +// Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // -// -// ------------------------------------------------------------------------------------------------ +// +// ----------------------------------------------------------------------------------------------- namespace EAModelKit.Extensions { @@ -24,12 +24,15 @@ namespace EAModelKit.Extensions using AutofacSerilogIntegration; + using EAModelKit.Services.Dispatcher; using EAModelKit.Services.Logger; + using EAModelKit.Services.Selection; + using EAModelKit.Services.Version; using Microsoft.Extensions.Logging; /// - /// Extension class for + /// Extension class for /// public static class ContainerBuilderExtensions { @@ -46,6 +49,9 @@ public static void RegisterServices(this ContainerBuilder builder) .SingleInstance(); builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); } /// diff --git a/EA-ModelKit/Extensions/RepositoryExtensions.cs b/EA-ModelKit/Extensions/RepositoryExtensions.cs index 0ad1d66..7e04ab8 100644 --- a/EA-ModelKit/Extensions/RepositoryExtensions.cs +++ b/EA-ModelKit/Extensions/RepositoryExtensions.cs @@ -1,7 +1,7 @@ // ------------------------------------------------------------------------------------------------- -// +// // -// Copyright 2024 Starion Group S.A. +// Copyright (C) 2024 Starion Group S.A. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -9,14 +9,14 @@ // // http://www.apache.org/licenses/LICENSE-2.0 // -// Unless required by applicable law or agreed to in writing, softwareUseCases +// Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // -// -// ------------------------------------------------------------------------------------------------ +// +// ----------------------------------------------------------------------------------------------- namespace EAModelKit.Extensions { diff --git a/EA-ModelKit/Model/Wrappers/PackageWrapper.cs b/EA-ModelKit/Model/Wrappers/PackageWrapper.cs new file mode 100644 index 0000000..222af38 --- /dev/null +++ b/EA-ModelKit/Model/Wrappers/PackageWrapper.cs @@ -0,0 +1,104 @@ +// ------------------------------------------------------------------------------------------------- +// +// +// Copyright (C) 2024 Starion Group S.A. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +// ----------------------------------------------------------------------------------------------- + +namespace EAModelKit.Model.Wrappers +{ + using System; + using System.Collections.Generic; + using System.Linq; + + using EA; + + /// + /// Wrapper class for a + /// + public class PackageWrapper + { + /// + /// Initializes a new instance of the class. + /// + public PackageWrapper() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The associated + public PackageWrapper(IDualPackage package) + { + if (package == null) + { + throw new ArgumentNullException(nameof(package)); + } + + this.PackageName = package.Name; + this.ContainerId = package.ParentID; + this.PackageId = package.PackageID; + this.PackageGuid = package.PackageGUID; + this.RelatedElementId = package.Element?.ElementID; + } + + /// + /// Gets the ID of the associated , if applicable. If null, means that the + /// is the root package. + /// + public int? RelatedElementId { get; set; } + + /// + /// Gets the GUID of the + /// + public string PackageGuid { get; set; } + + /// + /// Gets the ID of the + /// + public int PackageId { get; set; } + + /// + /// Gets the ID of the container + /// + public int ContainerId { get; set; } + + /// + /// Gets the name of the + /// + public string PackageName { get; set; } + + /// + /// Queries nested id that are contained into a + /// + /// A collection of all available + /// The id of the container + /// A collection of all nested ids + public static IReadOnlyCollection QueryContainedPackagesId(IReadOnlyCollection packages, int containerId) + { + var nestedPackageIds = new List(); + + foreach (var nestedPackageId in packages.Where(x => x.ContainerId == containerId).Select(x => x.PackageId)) + { + nestedPackageIds.Add(nestedPackageId); + nestedPackageIds.AddRange(QueryContainedPackagesId(packages, nestedPackageId)); + } + + return nestedPackageIds; + } + } +} diff --git a/EA-ModelKit/Properties/AssemblyInfo.cs b/EA-ModelKit/Properties/AssemblyInfo.cs index c229399..c061d53 100644 --- a/EA-ModelKit/Properties/AssemblyInfo.cs +++ b/EA-ModelKit/Properties/AssemblyInfo.cs @@ -1,4 +1,23 @@ -using System.Reflection; +// ------------------------------------------------------------------------------------------------- +// +// +// Copyright (C) 2024 Starion Group S.A. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +// ----------------------------------------------------------------------------------------------- + using System.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/EA-ModelKit/Services/Dispatcher/DispatcherService.cs b/EA-ModelKit/Services/Dispatcher/DispatcherService.cs new file mode 100644 index 0000000..9b627f4 --- /dev/null +++ b/EA-ModelKit/Services/Dispatcher/DispatcherService.cs @@ -0,0 +1,89 @@ +// ------------------------------------------------------------------------------------------------- +// +// +// Copyright (C) 2024 Starion Group S.A. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +// ----------------------------------------------------------------------------------------------- + +namespace EAModelKit.Services.Dispatcher +{ + using System.Linq; + + using EA; + + using EAModelKit.Services.Logger; + using EAModelKit.Services.Selection; + + using Microsoft.Extensions.Logging; + + /// + /// The provides EA events abstraction layer and available actions entry point + /// + internal class DispatcherService : IDispatcherService + { + /// + /// Gets the injected + /// + private readonly ILoggerService logger; + + /// + /// Gets the injected + /// + private readonly ISelectionService selectionService; + + /// Initializes a new instance of the class. + /// The injected + /// The injected + public DispatcherService(ILoggerService logger, ISelectionService selectionService) + { + this.logger = logger; + this.selectionService = selectionService; + } + + /// + /// Handles the connection to EA + /// + /// The EA + public void Connect(Repository repository) + { + this.logger.InitializeService(repository); + this.logger.Log(LogLevel.Information, "EA Model-Kit plugin successfully connected to EA"); + } + + /// + /// Handles the disconnection to EA + /// + public void Disconnect() + { + this.logger.Log(LogLevel.Information, "EA Model-Kit plugin successfully disconnected to EA"); + } + + /// + /// Handles the Generic Export action + /// + /// The EA + public void OnGenericExport(Repository repository) + { + var selectedElements = this.selectionService.QuerySelectedElements(repository); + var elementsPerStereotype = selectedElements.GroupBy(x => x.Stereotype).ToDictionary(x => x.Key, x => x.ToList()); + + foreach (var elements in elementsPerStereotype) + { + this.logger.Log(LogLevel.Debug, "Found {0} Elements With Stereotype {1}", elements.Value.Count, elements.Key); + } + } + } +} diff --git a/EA-ModelKit/Services/Dispatcher/IDispatcherService.cs b/EA-ModelKit/Services/Dispatcher/IDispatcherService.cs new file mode 100644 index 0000000..30868ba --- /dev/null +++ b/EA-ModelKit/Services/Dispatcher/IDispatcherService.cs @@ -0,0 +1,47 @@ +// ------------------------------------------------------------------------------------------------- +// +// +// Copyright (C) 2024 Starion Group S.A. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +// ----------------------------------------------------------------------------------------------- + +namespace EAModelKit.Services.Dispatcher +{ + using EA; + + /// + /// The provides EA events abstraction layer and available actions entry point + /// + internal interface IDispatcherService + { + /// + /// Handles the connection to EA + /// + /// The EA + void Connect(Repository repository); + + /// + /// Handles the disconnection to EA + /// + void Disconnect(); + + /// + /// Handles the Generic Export action + /// + /// The EA + void OnGenericExport(Repository repository); + } +} diff --git a/EA-ModelKit/Services/Logger/ILoggerService.cs b/EA-ModelKit/Services/Logger/ILoggerService.cs index c44a5b4..1e1f105 100644 --- a/EA-ModelKit/Services/Logger/ILoggerService.cs +++ b/EA-ModelKit/Services/Logger/ILoggerService.cs @@ -1,7 +1,7 @@ // ------------------------------------------------------------------------------------------------- -// +// // -// Copyright 2024 Starion Group S.A. +// Copyright (C) 2024 Starion Group S.A. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -9,14 +9,14 @@ // // http://www.apache.org/licenses/LICENSE-2.0 // -// Unless required by applicable law or agreed to in writing, softwareUseCases +// Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // -// -// ------------------------------------------------------------------------------------------------ +// +// ----------------------------------------------------------------------------------------------- namespace EAModelKit.Services.Logger { diff --git a/EA-ModelKit/Services/Logger/LoggerService.cs b/EA-ModelKit/Services/Logger/LoggerService.cs index 332d8da..990f0a9 100644 --- a/EA-ModelKit/Services/Logger/LoggerService.cs +++ b/EA-ModelKit/Services/Logger/LoggerService.cs @@ -1,7 +1,7 @@ // ------------------------------------------------------------------------------------------------- -// +// // -// Copyright 2024 Starion Group S.A. +// Copyright (C) 2024 Starion Group S.A. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -9,14 +9,14 @@ // // http://www.apache.org/licenses/LICENSE-2.0 // -// Unless required by applicable law or agreed to in writing, softwareUseCases +// Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // -// -// ------------------------------------------------------------------------------------------------ +// +// ----------------------------------------------------------------------------------------------- namespace EAModelKit.Services.Logger { diff --git a/EA-ModelKit/Services/Selection/ISelectionService.cs b/EA-ModelKit/Services/Selection/ISelectionService.cs new file mode 100644 index 0000000..8ed5f19 --- /dev/null +++ b/EA-ModelKit/Services/Selection/ISelectionService.cs @@ -0,0 +1,39 @@ +// ------------------------------------------------------------------------------------------------- +// +// +// Copyright (C) 2024 Starion Group S.A. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +// ----------------------------------------------------------------------------------------------- + +namespace EAModelKit.Services.Selection +{ + using System.Collections.Generic; + + using EA; + + /// + /// The provides information about Element that are currently selected or contained by a selected package, supporting nesting. + /// + internal interface ISelectionService + { + /// + /// Queries all that are part of the current selection. + /// + /// The + /// A read-only collection of selected s + public IReadOnlyCollection QuerySelectedElements(Repository repository); + } +} diff --git a/EA-ModelKit/Services/Selection/SelectionService.cs b/EA-ModelKit/Services/Selection/SelectionService.cs new file mode 100644 index 0000000..ede5837 --- /dev/null +++ b/EA-ModelKit/Services/Selection/SelectionService.cs @@ -0,0 +1,126 @@ +// ------------------------------------------------------------------------------------------------- +// +// +// Copyright (C) 2024 Starion Group S.A. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// +// ----------------------------------------------------------------------------------------------- + +namespace EAModelKit.Services.Selection +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.Linq; + using System.Xml.Linq; + + using EA; + + using EAModelKit.Model.Wrappers; + + /// + /// The provides information about Element that are currently selected or contained by a selected package, supporting nesting. + /// + internal class SelectionService : ISelectionService + { + /// + /// Queries all that are part of the current selection. + /// + /// The + /// A read-only collection of selected s + public IReadOnlyCollection QuerySelectedElements(Repository repository) + { + var selectedPackagesId = QueryCurrentlySelectedPackagesId(repository); + + if (selectedPackagesId.Count == 0) + { + return [..repository.CurrentSelection.ElementSet.OfType()]; + } + + var existingPackages = QueriesAllExistingPackages(repository); + var allSelectedPackages = new List(selectedPackagesId); + + foreach (var selectedPackageId in selectedPackagesId) + { + allSelectedPackages.AddRange(PackageWrapper.QueryContainedPackagesId(existingPackages, selectedPackageId)); + } + + var sqlQuery = $"SELECT Object_ID from t_object WHERE Package_ID in ({string.Join(",", allSelectedPackages)}) AND Object_Type != 'Package'"; + var sqlResponse = repository.SQLQuery(sqlQuery); + + var xElement = XElement.Parse(sqlResponse); + var xRows = xElement.Descendants("Row"); + + var selectedElementsId = xRows.Select(r => int.Parse(r.Elements().First(MatchElementByName("Object_ID")).Value, + CultureInfo.InvariantCulture)).Distinct().ToList(); + + return selectedElementsId.Count == 0 ? [] : repository.GetElementSet(string.Join(",", selectedElementsId), 0).OfType().ToList(); + } + + /// + /// Queries s id that are part of the selection, without any nesting + /// + /// The + /// The of all selected package + private static HashSet QueryCurrentlySelectedPackagesId(IDualRepository repository) + { + var packagesId = new HashSet(); + + for (short selectionListIndex = 0; selectionListIndex < repository.CurrentSelection.List.Count; selectionListIndex++) + { + var item = (EAContext)repository.CurrentSelection.List.GetAt(selectionListIndex); + + if (item.BaseType == nameof(Package)) + { + packagesId.Add(item.ElementID); + } + } + + return packagesId; + } + + /// + /// Function that verifies that an matches a name + /// + /// The name that have to match + /// A + private static Func MatchElementByName(string matchingName) + { + return x => string.Equals(x.Name.LocalName, matchingName, StringComparison.InvariantCultureIgnoreCase); + } + + /// + /// Queries all that exists inside the current EA project + /// + /// The + /// A read-only collection of , for all Package that exists inside the current EA project + private static IReadOnlyCollection QueriesAllExistingPackages(IDualRepository repository) + { + const string sqlQuery = "SELECT package.Package_Id as PACKAGE_ID, package.Parent_Id as PARENT_ID from t_package package"; + var sqlResponse = repository.SQLQuery(sqlQuery); + var xElement = XElement.Parse(sqlResponse); + var xRows = xElement.Descendants("Row"); + + return + [ + ..xRows.Select(r => new PackageWrapper + { + PackageId = int.Parse(r.Elements().First(MatchElementByName("PACKAGE_ID")).Value, CultureInfo.InvariantCulture), + ContainerId = int.Parse(r.Elements().First(MatchElementByName("PARENT_ID")).Value, CultureInfo.InvariantCulture) + }) + ]; + } + } +} diff --git a/EA-ModelKit/Services/Version/IVersionService.cs b/EA-ModelKit/Services/Version/IVersionService.cs index a822482..c711662 100644 --- a/EA-ModelKit/Services/Version/IVersionService.cs +++ b/EA-ModelKit/Services/Version/IVersionService.cs @@ -1,7 +1,7 @@ // ------------------------------------------------------------------------------------------------- -// +// // -// Copyright 2024 Starion Group S.A. +// Copyright (C) 2024 Starion Group S.A. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -9,14 +9,14 @@ // // http://www.apache.org/licenses/LICENSE-2.0 // -// Unless required by applicable law or agreed to in writing, softwareUseCases +// Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // -// -// ------------------------------------------------------------------------------------------------ +// +// ----------------------------------------------------------------------------------------------- namespace EAModelKit.Services.Version { diff --git a/EA-ModelKit/Services/Version/VersionService.cs b/EA-ModelKit/Services/Version/VersionService.cs index feac0c5..1f548ae 100644 --- a/EA-ModelKit/Services/Version/VersionService.cs +++ b/EA-ModelKit/Services/Version/VersionService.cs @@ -1,7 +1,7 @@ // ------------------------------------------------------------------------------------------------- -// +// // -// Copyright 2024 Starion Group S.A. +// Copyright (C) 2024 Starion Group S.A. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -9,14 +9,14 @@ // // http://www.apache.org/licenses/LICENSE-2.0 // -// Unless required by applicable law or agreed to in writing, softwareUseCases +// Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // -// -// ------------------------------------------------------------------------------------------------ +// +// ----------------------------------------------------------------------------------------------- namespace EAModelKit.Services.Version {