diff --git a/lib/translators/ui5Framework.js b/lib/translators/ui5Framework.js index d5534f31e..7b20ad330 100644 --- a/lib/translators/ui5Framework.js +++ b/lib/translators/ui5Framework.js @@ -212,8 +212,18 @@ module.exports = { log.verbose(`Merging framework tree into project tree "${projectTree.metadata.name}"`); const queue = [projectTree]; + const processedProjects = []; while (queue.length) { const project = queue.shift(); + if (processedProjects.includes(project.id)) { + // projectTree must be duplicate free. A second occurrence of the same project + // is always the same object. Therefore a single processing needs to be ensured. + // Otherwise the isFrameworkProject check would detect framework dependencies added + // at an earlier processing of the project and yield incorrect logging. + log.verbose(`Project ${project.metadata.name} (${project.id}) has already been processed`); + return; + } + processedProjects.push(project.id); project.dependencies = project.dependencies.filter((depProject) => { if (utils.isFrameworkProject(depProject)) { diff --git a/test/lib/translators/ui5Framework.integration.js b/test/lib/translators/ui5Framework.integration.js index 0fbda9cff..384692a50 100644 --- a/test/lib/translators/ui5Framework.integration.js +++ b/test/lib/translators/ui5Framework.integration.js @@ -34,6 +34,10 @@ test.beforeEach((t) => { sinon.stub(lockfile, "lock").yieldsAsync(); sinon.stub(lockfile, "unlock").yieldsAsync(); + const testLogger = logger.getLogger(); + sinon.stub(logger, "getLogger").returns(testLogger); + t.context.logInfoSpy = sinon.spy(testLogger, "info"); + mock("mkdirp", sinon.stub().resolves()); // Re-require to ensure that mocked modules are used @@ -149,22 +153,25 @@ function defineTest(testName, { logger.setLevel("verbose"); } + const testDependency = { + id: "test-dependency-id", + version: "4.5.6", + path: path.join(fakeBaseDir, "project-test-dependency"), + dependencies: [] + }; const translatorTree = { id: "test-application-id", version: "1.2.3", path: path.join(fakeBaseDir, "project-test-application"), dependencies: [ - { - id: "test-dependency-id", - version: "4.5.6", - path: path.join(fakeBaseDir, "project-test-dependency"), - dependencies: [] - }, + testDependency, { id: "test-dependency-no-framework-id", version: "7.8.9", path: path.join(fakeBaseDir, "project-test-dependency-no-framework"), - dependencies: [] + dependencies: [ + testDependency + ] }, { id: "test-dependency-framework-old-spec-version-id", @@ -377,96 +384,98 @@ function defineTest(testName, { .resolves(distributionMetadata); } - const expectedTree = project({ - _level: 0, - name: "test-application", - version: "1.2.3", - type: "application", + const testDependencyProject = project({ + _level: 1, + name: "test-dependency", + version: "4.5.6", + type: "library", framework: { + version: "1.99.0", name: frameworkName, - version: "1.75.0", libraries: [ { name: "sap.ui.lib1" }, { - name: "sap.ui.lib4", + name: "sap.ui.lib2" + }, + { + name: "sap.ui.lib5", optional: true }, { - name: "sap.ui.lib8", + name: "sap.ui.lib6", development: true + }, + { + name: "sap.ui.lib8", + optional: true } ] }, dependencies: [ - project({ + frameworkProject({ _level: 1, - name: "test-dependency", - version: "4.5.6", - type: "library", - framework: { - version: "1.99.0", - name: frameworkName, - libraries: [ - { - name: "sap.ui.lib1" - }, - { - name: "sap.ui.lib2" - }, - { - name: "sap.ui.lib5", - optional: true - }, - { - name: "sap.ui.lib6", - development: true - }, - { - name: "sap.ui.lib8", - optional: true - } - ] - }, + name: "sap.ui.lib1", + }), + frameworkProject({ + _level: 1, + name: "sap.ui.lib2", dependencies: [ frameworkProject({ - _level: 1, - name: "sap.ui.lib1", - }), - frameworkProject({ - _level: 1, - name: "sap.ui.lib2", + _level: 2, + name: "sap.ui.lib3", dependencies: [ frameworkProject({ - _level: 2, - name: "sap.ui.lib3", + name: "sap.ui.lib4", + _level: 1, dependencies: [ frameworkProject({ - name: "sap.ui.lib4", _level: 1, - dependencies: [ - frameworkProject({ - _level: 1, - name: "sap.ui.lib1" - }) - ] + name: "sap.ui.lib1" }) ] }) ] - }), - frameworkProject({ - _level: 1, - name: "sap.ui.lib8", }) ] }), + frameworkProject({ + _level: 1, + name: "sap.ui.lib8", + }) + ] + }); + const expectedTree = project({ + _level: 0, + name: "test-application", + version: "1.2.3", + type: "application", + framework: { + name: frameworkName, + version: "1.75.0", + libraries: [ + { + name: "sap.ui.lib1" + }, + { + name: "sap.ui.lib4", + optional: true + }, + { + name: "sap.ui.lib8", + development: true + } + ] + }, + dependencies: [ + testDependencyProject, project({ _level: 1, name: "test-dependency-no-framework", version: "7.8.9", - type: "library" + type: "library", + dependencies: [testDependencyProject] }), project({ _level: 1, @@ -506,6 +515,10 @@ function defineTest(testName, { const tree = await normalizer.generateProjectTree(); t.deepEqual(tree, expectedTree, "Returned tree should be correct"); + const frameworkLibAlreadyAddedInfoLogged = (t.context.logInfoSpy.getCalls() + .map(($) => $.firstArg) + .findIndex(($) => $.includes("defines a dependency to the UI5 framework library")) !== -1); + t.false(frameworkLibAlreadyAddedInfoLogged, "No info regarding already added UI5 framework libraries logged"); }); }