From 51e479ec9e59e76efb28e2460f5d81fb239cee68 Mon Sep 17 00:00:00 2001 From: samatstarion Date: Sat, 28 Dec 2024 22:13:33 +0100 Subject: [PATCH] [Implement] XlReportGenerator --- .../XlReportGeneratorTestFixture.cs | 87 +++++ .../Generators/XlReportGenerator.cs | 312 ++++++++++++------ 2 files changed, 306 insertions(+), 93 deletions(-) create mode 100644 uml4net.Reporting.Tests/Generators/XlReportGeneratorTestFixture.cs diff --git a/uml4net.Reporting.Tests/Generators/XlReportGeneratorTestFixture.cs b/uml4net.Reporting.Tests/Generators/XlReportGeneratorTestFixture.cs new file mode 100644 index 00000000..90c9b824 --- /dev/null +++ b/uml4net.Reporting.Tests/Generators/XlReportGeneratorTestFixture.cs @@ -0,0 +1,87 @@ +// ------------------------------------------------------------------------------------------------- +// +// +// Copyright 2019-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 uml4net.Reporting.Tests.Generators +{ + using System.Collections.Generic; + using System.IO; + + using Microsoft.Extensions.Logging; + + using NUnit.Framework; + + using Reporting.Generators; + + using Serilog; + + [TestFixture] + public class XlReportGeneratorTestFixture + { + private ILoggerFactory loggerFactory; + + private XlReportGenerator xlReportGenerator; + + private FileInfo umlModelFileInfo; + + private FileInfo sysml2ModelFileInfo; + + [SetUp] + public void SetUp() + { + Log.Logger = new LoggerConfiguration() + .MinimumLevel.Verbose() + .WriteTo.Console() + .CreateLogger(); + + this.loggerFactory = LoggerFactory.Create(builder => + { + builder.AddSerilog(); + }); + + this.umlModelFileInfo = new FileInfo(Path.Combine(TestContext.CurrentContext.TestDirectory, "TestData", "UML.xmi")); + this.sysml2ModelFileInfo = new FileInfo(Path.Combine(TestContext.CurrentContext.TestDirectory, "TestData", "SysML.uml")); + } + + [Test] + public void Verify_that_the_report_generator_generates_a_report_of_uml() + { + this.xlReportGenerator = new XlReportGenerator(this.loggerFactory); + + var reportFileInfo = new FileInfo(Path.Combine(TestContext.CurrentContext.TestDirectory, "uml-xl-report.xlsx")); + + var pathmap = new Dictionary(); + + Assert.That(() => this.xlReportGenerator.GenerateReport(this.umlModelFileInfo, this.umlModelFileInfo.Directory, pathmap, reportFileInfo), Throws.Nothing); + } + + [Test] + public void Verify_that_the_report_generator_generates_a_report_of_sysml2() + { + this.xlReportGenerator = new XlReportGenerator(this.loggerFactory); + + var reportFileInfo = new FileInfo(Path.Combine(TestContext.CurrentContext.TestDirectory, "sysml2-xl-report.xlsx")); + + var pathmap = new Dictionary(); + pathmap.Add("pathmap://UML_LIBRARIES/UMLPrimitiveTypes.library.uml", Path.Combine("TestData", "PrimitiveTypes.xmi")); + + Assert.That(() => this.xlReportGenerator.GenerateReport(this.sysml2ModelFileInfo, this.umlModelFileInfo.Directory, pathmap, reportFileInfo), Throws.Nothing); + } + } +} \ No newline at end of file diff --git a/uml4net.Reporting/Generators/XlReportGenerator.cs b/uml4net.Reporting/Generators/XlReportGenerator.cs index 2c4d144f..e7b6c0cf 100644 --- a/uml4net.Reporting/Generators/XlReportGenerator.cs +++ b/uml4net.Reporting/Generators/XlReportGenerator.cs @@ -25,13 +25,19 @@ namespace uml4net.Reporting.Generators using System.Data; using System.Diagnostics; using System.IO; + using System.Linq; using System.Reflection; using ClosedXML.Excel; - using Extensions; + using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; + using uml4net.Classification; + using uml4net.CommonStructure; + using uml4net.Extensions; + using uml4net.SimpleClassifiers; + using uml4net.StructuredClassifiers; using uml4net.Packages; /// @@ -98,20 +104,26 @@ public void GenerateReport(FileInfo modelPath, DirectoryInfo rootDirectory, Dict this.logger.LogInformation("Start Generating Excel report tables"); - //var rootPackage = this.LoadRootPackage(modelPath); - IPackage rootPackage = null; + var xmiReaderResult = this.LoadPackages(modelPath, rootDirectory, pathMap); + + var packages = xmiReaderResult.Root.QueryPackages().ToList(); + packages.AddRange(xmiReaderResult.Packages); - var packages = rootPackage.QueryPackages(); + packages = packages.Distinct().ToList(); using (var workbook = new XLWorkbook()) { - this.AddInfoSheet(workbook, rootPackage); + this.AddInfoSheet(workbook, xmiReaderResult.Root); this.AddIClassSheet(workbook, packages); - this.AddIEnumuerationSheet(workbook, packages); + this.AddIInterfaceSheet(workbook, packages); + + this.AddIEnumerationSheet(workbook, packages); + + this.AddIPrimitiveTypeSheet(workbook, packages); - this.AddIDataTypeSheet(workbook, packages); + this.AddOtherIDataTypeSheet(workbook, packages); this.logger.LogInformation("Saving report file to {0}", outputPath.FullName); @@ -159,51 +171,59 @@ private void AddInfoSheet(XLWorkbook workbook, IPackage rootPackage) /// private void AddIClassSheet(XLWorkbook workbook, IEnumerable packages) { - this.logger.LogDebug("Add IClass reports"); + this.logger.LogDebug("Add IClass report"); var classWorksheet = workbook.Worksheets.Add("Class"); var dataTable = new DataTable(); dataTable.Columns.Add("Class", typeof(string)); - dataTable.Columns.Add("Feature", typeof(string)); - dataTable.Columns.Add("EType", typeof(string)); + dataTable.Columns.Add("Qualified Name", typeof(string)); + dataTable.Columns.Add("IsAbstract", typeof(string)); + dataTable.Columns.Add("Generalizations", typeof(string)); + dataTable.Columns.Add("Property", typeof(string)); + dataTable.Columns.Add("Type", typeof(string)); dataTable.Columns.Add("Multiplicity", typeof(string)); dataTable.Columns.Add("IsContainment", typeof(string)); dataTable.Columns.Add("Documentation", typeof(string)); + dataTable.Columns.Add("Inheritance", typeof(string)); - //foreach (var package in packages) - //{ - // foreach (var eClass in package.EClassifiers.OfType().OrderBy(x => x.Name)) - // { - // var classDataRow = dataTable.NewRow(); - // classDataRow["Class"] = eClass.Name; - // classDataRow["Feature"] = "--"; - // classDataRow["EType"] = "--"; - // classDataRow["Multiplicity"] = "--"; - // classDataRow["IsContainment"] = "--"; - // classDataRow["Documentation"] = eClass.QueryRawDocumentation(); - // dataTable.Rows.Add(classDataRow); - - // foreach (var structuralFeature in eClass.EStructuralFeatures) - // { - // if (structuralFeature.Derived || structuralFeature.Transient) - // { - // continue; - // } - - // var structuralFeatureDataRow = dataTable.NewRow(); - // structuralFeatureDataRow["Class"] = eClass.Name; - // structuralFeatureDataRow["Feature"] = structuralFeature.Name; - // structuralFeatureDataRow["EType"] = structuralFeature.EType.Name; - // structuralFeatureDataRow["Multiplicity"] = $"{structuralFeature.LowerBound}:{structuralFeature.UpperBound}"; - // structuralFeatureDataRow["IsContainment"] = structuralFeature.QueryIsContainment(); - // structuralFeatureDataRow["Documentation"] = structuralFeature.QueryRawDocumentation(); - - // dataTable.Rows.Add(structuralFeatureDataRow); - // } - // } - //} + foreach (var package in packages) + { + foreach (var @class in package.PackagedElement.OfType().OrderBy(x => x.Name)) + { + var classDataRow = dataTable.NewRow(); + classDataRow["Class"] = @class.Name; + classDataRow["Qualified Name"] = @class.QualifiedName; + classDataRow["IsAbstract"] = @class.IsAbstract.ToString(); + classDataRow["Generalizations"] = string.Join(", ", @class.SuperClass.Select(o => o.Name)) ; + classDataRow["Property"] = "--"; + classDataRow["Type"] = "--"; + classDataRow["Multiplicity"] = "--"; + classDataRow["IsContainment"] = "--"; + classDataRow["Documentation"] = @class.QueryRawDocumentation(); + classDataRow["Inheritance"] = "--"; + dataTable.Rows.Add(classDataRow); + + foreach (var property in @class.QueryAllProperties()) + { + if (property.IsDerived || property.IsDerived || property.IsReadOnly) + { + continue; + } + + var propertyDataRow = dataTable.NewRow(); + propertyDataRow["Class"] = @class.Name; + propertyDataRow["Property"] = property.Name; + propertyDataRow["Type"] = property.QueryTypeName(); + propertyDataRow["Multiplicity"] = $"[{property.Lower}..{property.Upper}]"; + propertyDataRow["IsContainment"] = property.IsComposite.ToString(); + propertyDataRow["Documentation"] = property.QueryRawDocumentation(); + propertyDataRow["Inheritance"] = ((INamedElement)property.Owner).Name; + dataTable.Rows.Add(propertyDataRow); + } + } + } classWorksheet.Cell(1, 1).InsertTable(dataTable, "Classes", true); @@ -211,85 +231,191 @@ private void AddIClassSheet(XLWorkbook workbook, IEnumerable packages) } /// - /// Adds a worksheet to the workbook with EEnum data + /// Adds a worksheet to the workbook with Interface data + /// + /// + /// The target to which the Interface worksheet is added + /// + /// + /// The s that contain the Interface instances to report on + /// + private void AddIInterfaceSheet(XLWorkbook workbook, IEnumerable packages) + { + this.logger.LogDebug("Add IInterface report"); + + var interfaceWorksheet = workbook.Worksheets.Add("Interface"); + + var dataTable = new DataTable(); + + dataTable.Columns.Add("Interface", typeof(string)); + dataTable.Columns.Add("Qualified Name", typeof(string)); + dataTable.Columns.Add("Generalizations", typeof(string)); + dataTable.Columns.Add("Property", typeof(string)); + dataTable.Columns.Add("Type", typeof(string)); + dataTable.Columns.Add("Multiplicity", typeof(string)); + dataTable.Columns.Add("IsContainment", typeof(string)); + dataTable.Columns.Add("Documentation", typeof(string)); + + foreach (var package in packages) + { + foreach (var @interface in package.PackagedElement.OfType().OrderBy(x => x.Name)) + { + var classDataRow = dataTable.NewRow(); + classDataRow["Class"] = @interface.Name; + classDataRow["Qualified Name"] = @interface.QualifiedName; + classDataRow["IsAbstract"] = @interface.IsAbstract.ToString(); + classDataRow["Generalizations"] = string.Join(", ", @interface.QueryGeneral().Select(o => o.Name)); + classDataRow["Property"] = "--"; + classDataRow["Type"] = "--"; + classDataRow["Multiplicity"] = "--"; + classDataRow["IsContainment"] = "--"; + classDataRow["Documentation"] = @interface.QueryRawDocumentation(); + dataTable.Rows.Add(classDataRow); + + foreach (var property in @interface.OwnedAttribute) + { + if (property.IsDerived || property.IsDerived || property.IsReadOnly) + { + continue; + } + + var propertyDataRow = dataTable.NewRow(); + propertyDataRow["Class"] = @interface.Name; + propertyDataRow["Property"] = property.Name; + propertyDataRow["Type"] = property.QueryTypeName(); + propertyDataRow["Multiplicity"] = $"[{property.Lower}..{property.Upper}]"; + propertyDataRow["IsContainment"] = property.IsComposite.ToString(); + propertyDataRow["Documentation"] = property.QueryRawDocumentation(); + dataTable.Rows.Add(propertyDataRow); + } + } + } + + interfaceWorksheet.Cell(1, 1).InsertTable(dataTable, "Interfaces", true); + + this.FormatSheet(interfaceWorksheet); + } + + /// + /// Adds a worksheet to the workbook with IEnumeration data + /// + /// + /// The target to which the IEnumeration worksheet is added + /// + /// + /// The s that contain the IEnumeration instances to report on + /// + private void AddIEnumerationSheet(XLWorkbook workbook, IEnumerable packages) + { + var enumerationWorksheet = workbook.Worksheets.Add("Enumeration"); + + this.logger.LogDebug("Add IEnumeration report"); + + var dataTable = new DataTable(); + + dataTable.Columns.Add("Enumeration", typeof(string)); + dataTable.Columns.Add("Qualified Name", typeof(string)); + dataTable.Columns.Add("EnumerationLiteral", typeof(string)); + dataTable.Columns.Add("Documentation", typeof(string)); + + foreach (var package in packages) + { + foreach (var enumeration in package.PackagedElement.OfType().OrderBy(x => x.Name)) + { + var enumerationDataRow = dataTable.NewRow(); + enumerationDataRow["Enumeration"] = enumeration.Name; + enumerationDataRow["Qualified Name"] = enumeration.QualifiedName; + enumerationDataRow["EnumerationLiteral"] = "--"; + enumerationDataRow["Documentation"] = enumeration.QueryRawDocumentation(); + dataTable.Rows.Add(enumerationDataRow); + + foreach (var enumerationLiteral in enumeration.OwnedLiteral) + { + var enumerationLiteralDataRow = dataTable.NewRow(); + enumerationLiteralDataRow["Enumeration"] = enumeration.Name; + enumerationLiteralDataRow["EnumerationLiteral"] = enumerationLiteral.Name; + enumerationLiteralDataRow["Documentation"] = enumerationLiteral.QueryRawDocumentation(); + dataTable.Rows.Add(enumerationLiteralDataRow); + } + } + } + + enumerationWorksheet.Cell(1, 1).InsertTable(dataTable, "Enumerations", true); + + this.FormatSheet(enumerationWorksheet); + } + + /// + /// Adds a worksheet to the workbook with IPrimitiveType data /// /// - /// The target to which the EEnum worksheet is added + /// The target to which the IPrimitiveType worksheet is added /// /// - /// The s that contain the EEnum instances to report on + /// The s that contain the IPrimitiveType instances to report on /// - private void AddIEnumuerationSheet(XLWorkbook workbook, IEnumerable packages) + private void AddIPrimitiveTypeSheet(XLWorkbook workbook, IEnumerable packages) { - var enumWorksheet = workbook.Worksheets.Add("EEnum"); + var primitiveTypeWorksheet = workbook.Worksheets.Add("PrimitiveType"); - this.logger.LogDebug("Add EEnum reports"); + this.logger.LogDebug("Add IPrimitiveType report"); var dataTable = new DataTable(); - dataTable.Columns.Add("Enumueration", typeof(string)); - dataTable.Columns.Add("Literal", typeof(string)); + dataTable.Columns.Add("PrimitiveType", typeof(string)); dataTable.Columns.Add("Documentation", typeof(string)); - //foreach (var package in packages) - //{ - // foreach (var eEnum in package.EClassifiers.OfType().OrderBy(x => x.Name)) - // { - // var enumDataRow = dataTable.NewRow(); - // enumDataRow["Enum"] = eEnum.Name; - // enumDataRow["Literal"] = "--"; - // enumDataRow["Documentation"] = eEnum.QueryRawDocumentation(); - // dataTable.Rows.Add(enumDataRow); - - // foreach (var eEnumLiteral in eEnum.ELiterals) - // { - // var eEnumLiteralRow = dataTable.NewRow(); - // eEnumLiteralRow["Enum"] = eEnum.Name; - // eEnumLiteralRow["Literal"] = eEnumLiteral.Name; - // eEnumLiteralRow["Documentation"] = eEnumLiteral.QueryRawDocumentation(); - // dataTable.Rows.Add(eEnumLiteralRow); - // } - // } - //} - - enumWorksheet.Cell(1, 1).InsertTable(dataTable, "Enums", true); - - this.FormatSheet(enumWorksheet); + foreach (var package in packages) + { + foreach (var primitiveType in package.PackagedElement + .OfType() + .OrderBy(x => x.Name)) + { + var dataTypeRow = dataTable.NewRow(); + dataTypeRow["PrimitiveType"] = primitiveType.Name; + dataTypeRow["Documentation"] = primitiveType.QueryRawDocumentation(); + dataTable.Rows.Add(dataTypeRow); + } + } + + primitiveTypeWorksheet.Cell(1, 1).InsertTable(dataTable, "PrimitiveTypes", true); + + this.FormatSheet(primitiveTypeWorksheet); } /// - /// Adds a worksheet to the workbook with EDataType data + /// Adds a worksheet to the workbook with IDataType data (except for IEnumerations and PrimitiveTypes) /// /// - /// The target to which the EDataType worksheet is added + /// The target to which the IDataType worksheet is added /// /// - /// The s that contain the EDataType instances to report on + /// The s that contain the IDataType instances to report on /// - private void AddIDataTypeSheet(XLWorkbook workbook, IEnumerable packages) + private void AddOtherIDataTypeSheet(XLWorkbook workbook, IEnumerable packages) { - var dataTypeWorksheet = workbook.Worksheets.Add("EDataType"); + var dataTypeWorksheet = workbook.Worksheets.Add("DataType"); - this.logger.LogDebug("Add EDataType reports"); + this.logger.LogDebug("Add IDataType report"); var dataTable = new DataTable(); dataTable.Columns.Add("DataType", typeof(string)); dataTable.Columns.Add("Documentation", typeof(string)); - //foreach (var package in packages) - //{ - // foreach (var eDataType in package.EClassifiers - // .OfType() - // .Where(x => !(x is EEnum)) - // .OrderBy(x => x.Name)) - // { - // var dataTypeRow = dataTable.NewRow(); - // dataTypeRow["DataType"] = eDataType.Name; - // dataTypeRow["Documentation"] = eDataType.QueryRawDocumentation(); - // dataTable.Rows.Add(dataTypeRow); - // } - //} + foreach (var package in packages) + { + foreach (var eDataType in package.PackagedElement + .OfType() + .Where(x => x is not IEnumeration && x is not IPrimitiveType) + .OrderBy(x => x.Name)) + { + var dataTypeRow = dataTable.NewRow(); + dataTypeRow["DataType"] = eDataType.Name; + dataTypeRow["Documentation"] = eDataType.QueryRawDocumentation(); + dataTable.Rows.Add(dataTypeRow); + } + } dataTypeWorksheet.Cell(1, 1).InsertTable(dataTable, "DataTypes", true);