From faba42b201f52418362b23c35209481fc00b682c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 7 Jul 2025 17:25:45 +0000 Subject: [PATCH 1/5] Initial plan From 3ecab5a8e3f75190762762125d37be6cd7e75465 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 7 Jul 2025 17:46:19 +0000 Subject: [PATCH 2/5] Convert connectionStore.test.ts from TypeMoq to Sinon - basic conversion --- test/unit/connectionStore.test.ts | 103 +++++++++++++++++------------- 1 file changed, 59 insertions(+), 44 deletions(-) diff --git a/test/unit/connectionStore.test.ts b/test/unit/connectionStore.test.ts index eeab3f4147..ef041113c9 100644 --- a/test/unit/connectionStore.test.ts +++ b/test/unit/connectionStore.test.ts @@ -3,58 +3,73 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as TypeMoq from "typemoq"; -import * as vscode from "vscode"; -import { ConnectionStore } from "../../src/models/connectionStore"; -import { ICredentialStore } from "../../src/credentialstore/icredentialstore"; -import { Logger } from "../../src/models/logger"; -import { ConnectionConfig } from "../../src/connectionconfig/connectionconfig"; -import VscodeWrapper from "../../src/controllers/vscodeWrapper"; -import { expect } from "chai"; +import * as vscode from "vscode"; +import { ConnectionStore } from "../../src/models/connectionStore"; +import { ICredentialStore } from "../../src/credentialstore/icredentialstore"; +import { Logger } from "../../src/models/logger"; +import { ConnectionConfig } from "../../src/connectionconfig/connectionconfig"; +import VscodeWrapper from "../../src/controllers/vscodeWrapper"; +import { expect } from "chai"; import * as sinon from "sinon"; -suite("ConnectionStore Tests", () => { - let sandbox: sinon.SinonSandbox; - let connectionStore: ConnectionStore; - - let mockContext: TypeMoq.IMock; - let mockLogger: TypeMoq.IMock; - let mockCredentialStore: TypeMoq.IMock; - let mockConnectionConfig: TypeMoq.IMock; - let mockVscodeWrapper: TypeMoq.IMock; - - setup(async () => { - sandbox = sinon.createSandbox(); - - mockContext = TypeMoq.Mock.ofType(); - mockVscodeWrapper = TypeMoq.Mock.ofType(); - mockLogger = TypeMoq.Mock.ofType(); - mockCredentialStore = TypeMoq.Mock.ofType(); - mockConnectionConfig = TypeMoq.Mock.ofType(); - - mockConnectionConfig - .setup((c) => c.getConnections(TypeMoq.It.isAny())) - .returns(() => { - return Promise.resolve([]); - }); +suite("ConnectionStore Tests", () => { + let sandbox: sinon.SinonSandbox; + let connectionStore: ConnectionStore; + + let mockContext: sinon.SinonStubbedInstance; + let mockLogger: sinon.SinonStubbedInstance; + let mockCredentialStore: sinon.SinonStubbedInstance; + let mockConnectionConfig: sinon.SinonStubbedInstance; + let mockVscodeWrapper: sinon.SinonStubbedInstance; + + setup(async () => { + sandbox = sinon.createSandbox(); + + // Create stub for vscode.ExtensionContext (interface) + mockContext = {} as sinon.SinonStubbedInstance; + + // Create stub instances for classes + mockVscodeWrapper = sandbox.createStubInstance(VscodeWrapper); + mockLogger = sandbox.createStubInstance(Logger); + mockConnectionConfig = sandbox.createStubInstance(ConnectionConfig); + + // Create stub for ICredentialStore (interface) + mockCredentialStore = {} as sinon.SinonStubbedInstance; + + // Set up the getConnections method to return an empty array + mockConnectionConfig.getConnections.resolves([]); + + // Set up the initialized property to return a resolved promise + const resolvedDeferred = { + promise: Promise.resolve(), + resolve: () => {}, + reject: () => {}, + then: (onfulfilled?: () => void) => { + if (onfulfilled) { + onfulfilled(); + } + return Promise.resolve(); + } + }; + sandbox.stub(mockConnectionConfig, "initialized").get(() => resolvedDeferred); }); teardown(() => { sandbox.restore(); }); - test("Initializes correctly", async () => { - expect(() => { - connectionStore = new ConnectionStore( - mockContext.object, - mockCredentialStore.object, - mockLogger.object, - mockConnectionConfig.object, - mockVscodeWrapper.object, - ); - }).to.not.throw(); - - await connectionStore.initialized; // Wait for initialization to complete + test("Initializes correctly", async () => { + expect(() => { + connectionStore = new ConnectionStore( + mockContext, + mockCredentialStore, + mockLogger, + mockConnectionConfig, + mockVscodeWrapper, + ); + }).to.not.throw(); + + await connectionStore.initialized; // Wait for initialization to complete }); test("formatCredentialId", () => { From 90cc808713869fa3393610f343a34f6d758dc6a0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 7 Jul 2025 17:47:30 +0000 Subject: [PATCH 3/5] Convert connectionStore.test.ts from TypeMoq to Sinon - complete conversion Co-authored-by: Benjin <1609827+Benjin@users.noreply.github.com> --- test/unit/connectionStore.test.ts | 122 +++--- test/unit/connectionStore.test.ts.backup | 534 +++++++++++++++++++++++ 2 files changed, 595 insertions(+), 61 deletions(-) create mode 100644 test/unit/connectionStore.test.ts.backup diff --git a/test/unit/connectionStore.test.ts b/test/unit/connectionStore.test.ts index ef041113c9..5a6f562913 100644 --- a/test/unit/connectionStore.test.ts +++ b/test/unit/connectionStore.test.ts @@ -1,8 +1,8 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + import * as vscode from "vscode"; import { ConnectionStore } from "../../src/models/connectionStore"; import { ICredentialStore } from "../../src/credentialstore/icredentialstore"; @@ -10,8 +10,8 @@ import { Logger } from "../../src/models/logger"; import { ConnectionConfig } from "../../src/connectionconfig/connectionconfig"; import VscodeWrapper from "../../src/controllers/vscodeWrapper"; import { expect } from "chai"; -import * as sinon from "sinon"; - +import * as sinon from "sinon"; + suite("ConnectionStore Tests", () => { let sandbox: sinon.SinonSandbox; let connectionStore: ConnectionStore; @@ -20,25 +20,25 @@ suite("ConnectionStore Tests", () => { let mockLogger: sinon.SinonStubbedInstance; let mockCredentialStore: sinon.SinonStubbedInstance; let mockConnectionConfig: sinon.SinonStubbedInstance; - let mockVscodeWrapper: sinon.SinonStubbedInstance; - + let mockVscodeWrapper: sinon.SinonStubbedInstance; + setup(async () => { sandbox = sinon.createSandbox(); // Create stub for vscode.ExtensionContext (interface) mockContext = {} as sinon.SinonStubbedInstance; - + // Create stub instances for classes mockVscodeWrapper = sandbox.createStubInstance(VscodeWrapper); mockLogger = sandbox.createStubInstance(Logger); mockConnectionConfig = sandbox.createStubInstance(ConnectionConfig); - + // Create stub for ICredentialStore (interface) mockCredentialStore = {} as sinon.SinonStubbedInstance; // Set up the getConnections method to return an empty array mockConnectionConfig.getConnections.resolves([]); - + // Set up the initialized property to return a resolved promise const resolvedDeferred = { promise: Promise.resolve(), @@ -49,15 +49,15 @@ suite("ConnectionStore Tests", () => { onfulfilled(); } return Promise.resolve(); - } + }, }; sandbox.stub(mockConnectionConfig, "initialized").get(() => resolvedDeferred); - }); - - teardown(() => { - sandbox.restore(); - }); - + }); + + teardown(() => { + sandbox.restore(); + }); + test("Initializes correctly", async () => { expect(() => { connectionStore = new ConnectionStore( @@ -70,45 +70,45 @@ suite("ConnectionStore Tests", () => { }).to.not.throw(); await connectionStore.initialized; // Wait for initialization to complete - }); - - test("formatCredentialId", () => { - const testServer = "localhost"; - const testDatabase = "TestDb"; - const testUser = "testUser"; - - let credentialId = ConnectionStore.formatCredentialId( - testServer, - testDatabase, - testUser, - ConnectionStore.CRED_MRU_USER, - false, // isConnectionString - ); - - expect(credentialId).to.equal( - "Microsoft.SqlTools|itemtype:Mru|server:localhost|db:TestDb|user:testUser", - ); - - credentialId = ConnectionStore.formatCredentialId( - testServer, - testDatabase, - testUser, - undefined, // itemType - true, // isConnectionString - ); - - expect(credentialId).to.equal( - "Microsoft.SqlTools|itemtype:Profile|server:localhost|db:TestDb|user:testUser|isConnectionString:true", - ); - - credentialId = ConnectionStore.formatCredentialId(testServer, testDatabase); - - expect(credentialId).to.equal( - "Microsoft.SqlTools|itemtype:Profile|server:localhost|db:TestDb", - ); - - credentialId = ConnectionStore.formatCredentialId(testServer); - - expect(credentialId).to.equal("Microsoft.SqlTools|itemtype:Profile|server:localhost"); - }); -}); + }); + + test("formatCredentialId", () => { + const testServer = "localhost"; + const testDatabase = "TestDb"; + const testUser = "testUser"; + + let credentialId = ConnectionStore.formatCredentialId( + testServer, + testDatabase, + testUser, + ConnectionStore.CRED_MRU_USER, + false, // isConnectionString + ); + + expect(credentialId).to.equal( + "Microsoft.SqlTools|itemtype:Mru|server:localhost|db:TestDb|user:testUser", + ); + + credentialId = ConnectionStore.formatCredentialId( + testServer, + testDatabase, + testUser, + undefined, // itemType + true, // isConnectionString + ); + + expect(credentialId).to.equal( + "Microsoft.SqlTools|itemtype:Profile|server:localhost|db:TestDb|user:testUser|isConnectionString:true", + ); + + credentialId = ConnectionStore.formatCredentialId(testServer, testDatabase); + + expect(credentialId).to.equal( + "Microsoft.SqlTools|itemtype:Profile|server:localhost|db:TestDb", + ); + + credentialId = ConnectionStore.formatCredentialId(testServer); + + expect(credentialId).to.equal("Microsoft.SqlTools|itemtype:Profile|server:localhost"); + }); +}); diff --git a/test/unit/connectionStore.test.ts.backup b/test/unit/connectionStore.test.ts.backup new file mode 100644 index 0000000000..ce190f70ce --- /dev/null +++ b/test/unit/connectionStore.test.ts.backup @@ -0,0 +1,534 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as vscode from "vscode"; +import { ConnectionStore } from "../../src/models/connectionStore"; +import { ICredentialStore } from "../../src/credentialstore/icredentialstore"; +import { Logger } from "../../src/models/logger"; +import { ConnectionConfig } from "../../src/connectionconfig/connectionconfig"; +import VscodeWrapper from "../../src/controllers/vscodeWrapper"; +import { expect } from "chai"; +import * as sinon from "sinon"; + +suite("ObjectExplorerDragAndDropController Tests", () => { + let sandbox: sinon.SinonSandbox; + let mockVscodeWrapper: sinon.SinonStubbedInstance; + let mockConnectionStore: sinon.SinonStubbedInstance; + let mockLogger: sinon.SinonStubbedInstance; + let controller: ObjectExplorerDragAndDropController; + let getQualifiedNameStub: sinon.SinonStub; + let mockConnectionConfig: sinon.SinonStubbedInstance; + + const TEST_ROOT_GROUP_ID = "test-root-group-id"; + + setup(() => { + sandbox = sinon.createSandbox(); + mockVscodeWrapper = sandbox.createStubInstance(VscodeWrapper); + mockConnectionStore = sandbox.createStubInstance(ConnectionStore); + mockLogger = sandbox.createStubInstance(Logger); + mockConnectionConfig = sandbox.createStubInstance(ConnectionConfig); + + sandbox.stub(Logger, "create").returns(mockLogger); + + getQualifiedNameStub = sandbox.stub(ObjectExplorerUtils, "getQualifiedName"); + + sandbox.stub(mockConnectionStore, "rootGroupId").get(() => TEST_ROOT_GROUP_ID); + sandbox.stub(mockConnectionStore, "connectionConfig").get(() => mockConnectionConfig); + + controller = new ObjectExplorerDragAndDropController( + mockVscodeWrapper, + mockConnectionStore, + ); + }); + + teardown(() => { + sandbox.restore(); + }); + + suite("handleDrag", () => { + test("should handle drag for ConnectionNode", () => { + // Create mock connection profile + const mockProfile: IConnectionProfile = { + id: "conn1", + server: "server1", + database: "db1", + authenticationType: "Integrated", + user: "", + password: "", + savePassword: false, + groupId: TEST_ROOT_GROUP_ID, + } as IConnectionProfile; + + // Create mock connection node + const mockConnectionNode = new ConnectionNode(mockProfile); + + // Create mock data transfer + const mockDataTransfer = new vscode.DataTransfer(); + + // Mock ObjectExplorerUtils.getQualifiedName + const mockQualifiedName = "server1.db1"; + getQualifiedNameStub.returns(mockQualifiedName); + + // Call handleDrag + controller.handleDrag( + [mockConnectionNode], + mockDataTransfer, + {} as vscode.CancellationToken, + ); + + // Verify OE_MIME_TYPE data was set + const oeData = mockDataTransfer.get("application/vnd.code.tree.objectExplorer"); + expect(oeData, "OE_MIME_TYPE data should exist").to.exist; + expect(oeData.value, "OE data should match expected structure").to.deep.equal({ + name: mockConnectionNode.label.toString(), + type: "connection", + id: mockProfile.id, + isConnectionOrGroup: true, + }); + + // Verify TEXT_MIME_TYPE data was set + const textData = mockDataTransfer.get("text/plain"); + expect(textData, "TEXT_MIME_TYPE data should exist").to.exist; + expect(textData.value, "Text data should match qualified name").to.equal( + mockQualifiedName, + ); + }); + + test("should handle drag for ConnectionGroupNode", () => { + // Create mock connection group + const mockGroup: IConnectionGroup = { + id: "group1", + name: "Test Group", + parentId: TEST_ROOT_GROUP_ID, + description: "Test group description", + }; + + // Create mock connection group node + const mockGroupNode = new ConnectionGroupNode(mockGroup); + + // Create mock data transfer + const mockDataTransfer = new vscode.DataTransfer(); + + // Call handleDrag + controller.handleDrag( + [mockGroupNode], + mockDataTransfer, + {} as vscode.CancellationToken, + ); + + // Verify OE_MIME_TYPE data was set + const oeData = mockDataTransfer.get("application/vnd.code.tree.objectExplorer"); + expect(oeData, "OE_MIME_TYPE data should exist").to.exist; + expect(oeData.value, "OE data should match expected structure").to.deep.equal({ + name: mockGroupNode.label.toString(), + type: "connectionGroup", + id: mockGroup.id, + isConnectionOrGroup: true, + }); + + // Should NOT call getQualifiedName for ConnectionGroupNode + expect(getQualifiedNameStub.notCalled, "getQualifiedName should not be called").to.be + .true; + }); + + test("should handle drag for regular TreeNodeInfo with only TEXT_MIME_TYPE", () => { + // Create mock tree node info + const mockTreeNode = new TreeNodeInfo( + "testNode", + { + type: "table", + filterable: false, + hasFilters: false, + subType: "", + }, + vscode.TreeItemCollapsibleState.None, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + ); + + // Create mock data transfer + const mockDataTransfer = new vscode.DataTransfer(); + + // Mock ObjectExplorerUtils.getQualifiedName + const mockQualifiedName = "server1.db1.table1"; + getQualifiedNameStub.returns(mockQualifiedName); + + // Call handleDrag + controller.handleDrag([mockTreeNode], mockDataTransfer, {} as vscode.CancellationToken); + + // Verify OE_MIME_TYPE data was NOT set + const oeData = mockDataTransfer.get("application/vnd.code.tree.objectExplorer"); + expect(oeData, "OE_MIME_TYPE data should not exist").to.be.undefined; + + // Verify TEXT_MIME_TYPE data was set + const textData = mockDataTransfer.get("text/plain"); + expect(textData, "TEXT_MIME_TYPE data should exist").to.exist; + expect(textData.value, "Text data should match qualified name").to.equal( + mockQualifiedName, + ); + }); + }); + + suite("handleDrop", () => { + test("should handle drop of connection onto connection group successfully", async () => { + // Create mock connection profile + const mockProfile: IConnectionProfile = { + id: "conn1", + server: "server1", + database: "db1", + authenticationType: "Integrated", + user: "", + password: "", + savePassword: false, + groupId: "old-group-id", + } as IConnectionProfile; + + // Create mock connection group + const mockGroup: IConnectionGroup = { + id: "target-group-id", + name: "Target Group", + parentId: TEST_ROOT_GROUP_ID, + description: "Target group description", + }; + + // Create mock target group node + const mockTargetGroupNode = new ConnectionGroupNode(mockGroup); + + // Create mock data transfer with connection drag data + const mockDataTransfer = new vscode.DataTransfer(); + const dragData = { + name: "Test Connection", + type: "connection" as const, + id: mockProfile.id, + isConnectionOrGroup: true, + }; + mockDataTransfer.set( + "application/vnd.code.tree.objectExplorer", + new vscode.DataTransferItem(dragData), + ); + + // Mock connection store methods + (mockConnectionStore.connectionConfig.getConnectionById as sinon.SinonStub).resolves( + mockProfile, + ); + (mockConnectionStore.connectionConfig.updateConnection as sinon.SinonStub).resolves(); + + // Call handleDrop + await controller.handleDrop( + mockTargetGroupNode, + mockDataTransfer, + {} as vscode.CancellationToken, + ); + + expect( + (mockConnectionStore.connectionConfig.updateConnection as sinon.SinonStub) + .calledOnce, + "updateConnection should be called once", + ).to.be.true; + expect( + (mockConnectionStore.connectionConfig.updateConnection as sinon.SinonStub) + .args[0][0].groupId, + "Updated connection groupId should match target group id", + ).to.equal(mockGroup.id); + }); + + test("should handle drop of connection group onto another connection group successfully", async () => { + // Create mock connection group to be moved + const mockSourceGroup: IConnectionGroup = { + id: "source-group-id", + name: "Source Group", + parentId: "old-parent-id", + description: "Source group description", + }; + + // Create mock target connection group + const mockTargetGroup: IConnectionGroup = { + id: "target-group-id", + name: "Target Group", + parentId: TEST_ROOT_GROUP_ID, + description: "Target group description", + }; + + // Create mock target group node + const mockTargetGroupNode = new ConnectionGroupNode(mockTargetGroup); + + // Create mock data transfer with group drag data + const mockDataTransfer = new vscode.DataTransfer(); + const dragData = { + name: "Source Group", + type: "connectionGroup" as const, + id: mockSourceGroup.id, + isConnectionOrGroup: true, + }; + mockDataTransfer.set( + "application/vnd.code.tree.objectExplorer", + new vscode.DataTransferItem(dragData), + ); + + // Mock connection store methods + (mockConnectionStore.connectionConfig.getGroupById as sinon.SinonStub).returns( + mockSourceGroup, + ); + (mockConnectionStore.connectionConfig.updateGroup as sinon.SinonStub).resolves(); + + // Call handleDrop + await controller.handleDrop( + mockTargetGroupNode, + mockDataTransfer, + {} as vscode.CancellationToken, + ); + + // Verify group was retrieved and updated + expect( + (mockConnectionStore.connectionConfig.updateGroup as sinon.SinonStub).calledOnce, + "updateGroup should be called once", + ).to.be.true; + expect( + (mockConnectionStore.connectionConfig.updateGroup as sinon.SinonStub).args[0][0] + .parentId, + "Updated group parentId should match target group id", + ).to.equal(mockTargetGroup.id); + }); + + test("should handle drop onto root (undefined target) successfully", async () => { + // Create mock connection profile + const mockProfile: IConnectionProfile = { + id: "conn1", + server: "server1", + database: "db1", + authenticationType: "Integrated", + user: "", + password: "", + savePassword: false, + groupId: "old-group-id", + } as IConnectionProfile; + + // Create mock data transfer with connection drag data + const mockDataTransfer = new vscode.DataTransfer(); + const dragData = { + name: "Test Connection", + type: "connection" as const, + id: mockProfile.id, + isConnectionOrGroup: true, + }; + mockDataTransfer.set( + "application/vnd.code.tree.objectExplorer", + new vscode.DataTransferItem(dragData), + ); + + // Mock connection store methods + (mockConnectionStore.connectionConfig.getConnectionById as sinon.SinonStub).resolves( + mockProfile, + ); + (mockConnectionStore.connectionConfig.updateConnection as sinon.SinonStub).resolves(); + + // Call handleDrop with undefined target (root) + await controller.handleDrop( + undefined, + mockDataTransfer, + {} as vscode.CancellationToken, + ); + + // Verify connection was updated to root group + expect( + (mockConnectionStore.connectionConfig.updateConnection as sinon.SinonStub) + .calledOnce, + "updateConnection should be called once", + ).to.be.true; + expect( + (mockConnectionStore.connectionConfig.updateConnection as sinon.SinonStub) + .args[0][0].groupId, + "Updated connection groupId should match root group id", + ).to.equal(TEST_ROOT_GROUP_ID); + }); + + test("should prevent dropping group into itself", async () => { + // Create mock connection group + const mockGroup: IConnectionGroup = { + id: "group1", + name: "Test Group", + parentId: "old-parent-id", + description: "Test group description", + }; + + // Create mock group node (same group as source and target) + const mockGroupNode = new ConnectionGroupNode(mockGroup); + + // Create mock data transfer with group drag data + const mockDataTransfer = new vscode.DataTransfer(); + const dragData = { + name: "Test Group", + type: "connectionGroup" as const, + id: mockGroup.id, + isConnectionOrGroup: true, + }; + mockDataTransfer.set( + "application/vnd.code.tree.objectExplorer", + new vscode.DataTransferItem(dragData), + ); + + // Mock connection store methods + (mockConnectionStore.connectionConfig.getGroupById as sinon.SinonStub).returns( + mockGroup, + ); + + // Call handleDrop + await controller.handleDrop( + mockGroupNode, + mockDataTransfer, + {} as vscode.CancellationToken, + ); + + expect( + (mockConnectionStore.connectionConfig.updateGroup as sinon.SinonStub).called, + "updateGroup should not be called", + ).to.be.false; + }); + + test("should handle drop with invalid drag data gracefully", async () => { + // Create mock data transfer with invalid drag data + const mockDataTransfer = new vscode.DataTransfer(); + const invalidDragData = { + name: "Test Item", + isConnectionOrGroup: false, // Invalid: should be true for processing + }; + mockDataTransfer.set( + "application/vnd.code.tree.objectExplorer", + new vscode.DataTransferItem(invalidDragData), + ); + + // Create mock target group node + const mockTargetGroup: IConnectionGroup = { + id: "target-group-id", + name: "Target Group", + parentId: TEST_ROOT_GROUP_ID, + description: "Target group description", + }; + const mockTargetGroupNode = new ConnectionGroupNode(mockTargetGroup); + + // Call handleDrop + await controller.handleDrop( + mockTargetGroupNode, + mockDataTransfer, + {} as vscode.CancellationToken, + ); + + // Verify no processing occurred + expect( + (mockConnectionStore.connectionConfig.updateConnection as sinon.SinonStub).called, + "updateConnection should not be called", + ).to.be.false; + expect( + (mockConnectionStore.connectionConfig.updateGroup as sinon.SinonStub).called, + "updateGroup should not be called", + ).to.be.false; + }); + + test("should handle drop with missing drag data gracefully", async () => { + // Create mock data transfer with no OE_MIME_TYPE data + const mockDataTransfer = new vscode.DataTransfer(); + + // Create mock target group node + const mockTargetGroup: IConnectionGroup = { + id: "target-group-id", + name: "Target Group", + parentId: TEST_ROOT_GROUP_ID, + description: "Target group description", + }; + const mockTargetGroupNode = new ConnectionGroupNode(mockTargetGroup); + + // Call handleDrop + await controller.handleDrop( + mockTargetGroupNode, + mockDataTransfer, + {} as vscode.CancellationToken, + ); + + // Verify no processing occurred + expect( + (mockConnectionStore.connectionConfig.updateConnection as sinon.SinonStub).called, + "updateConnection should not be called", + ).to.be.false; + expect( + (mockConnectionStore.connectionConfig.updateGroup as sinon.SinonStub).called, + "updateGroup should not be called", + ).to.be.false; + }); + + test("should handle drop with non-connection/group target gracefully", async () => { + // Create mock connection profile + const mockProfile: IConnectionProfile = { + id: "conn1", + server: "server1", + database: "db1", + authenticationType: "Integrated", + user: "", + password: "", + savePassword: false, + groupId: "old-group-id", + } as IConnectionProfile; + + // Create mock data transfer with connection drag data + const mockDataTransfer = new vscode.DataTransfer(); + const dragData = { + name: "Test Connection", + type: "connection" as const, + id: mockProfile.id, + isConnectionOrGroup: true, + }; + mockDataTransfer.set( + "application/vnd.code.tree.objectExplorer", + new vscode.DataTransferItem(dragData), + ); + + // Create mock regular tree node as target (not a connection or group) + const mockTargetNode = new TreeNodeInfo( + "targetNode", + { + type: "table", + filterable: false, + hasFilters: false, + subType: "", + }, + vscode.TreeItemCollapsibleState.None, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + undefined, + ); + + // Call handleDrop + await controller.handleDrop( + mockTargetNode, + mockDataTransfer, + {} as vscode.CancellationToken, + ); + + // Verify nothing was moved + expect( + (mockConnectionStore.connectionConfig.updateConnection as sinon.SinonStub).called, + "updateConnection should not be called", + ).to.be.false; + expect( + (mockConnectionStore.connectionConfig.updateGroup as sinon.SinonStub).called, + "updateGroup should not be called", + ).to.be.false; + }); + }); +}); From 2ea5da23abbf5a09d3ddee0bfa90305170961d1b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 7 Jul 2025 17:48:53 +0000 Subject: [PATCH 4/5] Clean up backup file from connectionStore.test.ts conversion Co-authored-by: Benjin <1609827+Benjin@users.noreply.github.com> --- test/unit/connectionStore.test.ts.backup | 534 ----------------------- 1 file changed, 534 deletions(-) delete mode 100644 test/unit/connectionStore.test.ts.backup diff --git a/test/unit/connectionStore.test.ts.backup b/test/unit/connectionStore.test.ts.backup deleted file mode 100644 index ce190f70ce..0000000000 --- a/test/unit/connectionStore.test.ts.backup +++ /dev/null @@ -1,534 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as vscode from "vscode"; -import { ConnectionStore } from "../../src/models/connectionStore"; -import { ICredentialStore } from "../../src/credentialstore/icredentialstore"; -import { Logger } from "../../src/models/logger"; -import { ConnectionConfig } from "../../src/connectionconfig/connectionconfig"; -import VscodeWrapper from "../../src/controllers/vscodeWrapper"; -import { expect } from "chai"; -import * as sinon from "sinon"; - -suite("ObjectExplorerDragAndDropController Tests", () => { - let sandbox: sinon.SinonSandbox; - let mockVscodeWrapper: sinon.SinonStubbedInstance; - let mockConnectionStore: sinon.SinonStubbedInstance; - let mockLogger: sinon.SinonStubbedInstance; - let controller: ObjectExplorerDragAndDropController; - let getQualifiedNameStub: sinon.SinonStub; - let mockConnectionConfig: sinon.SinonStubbedInstance; - - const TEST_ROOT_GROUP_ID = "test-root-group-id"; - - setup(() => { - sandbox = sinon.createSandbox(); - mockVscodeWrapper = sandbox.createStubInstance(VscodeWrapper); - mockConnectionStore = sandbox.createStubInstance(ConnectionStore); - mockLogger = sandbox.createStubInstance(Logger); - mockConnectionConfig = sandbox.createStubInstance(ConnectionConfig); - - sandbox.stub(Logger, "create").returns(mockLogger); - - getQualifiedNameStub = sandbox.stub(ObjectExplorerUtils, "getQualifiedName"); - - sandbox.stub(mockConnectionStore, "rootGroupId").get(() => TEST_ROOT_GROUP_ID); - sandbox.stub(mockConnectionStore, "connectionConfig").get(() => mockConnectionConfig); - - controller = new ObjectExplorerDragAndDropController( - mockVscodeWrapper, - mockConnectionStore, - ); - }); - - teardown(() => { - sandbox.restore(); - }); - - suite("handleDrag", () => { - test("should handle drag for ConnectionNode", () => { - // Create mock connection profile - const mockProfile: IConnectionProfile = { - id: "conn1", - server: "server1", - database: "db1", - authenticationType: "Integrated", - user: "", - password: "", - savePassword: false, - groupId: TEST_ROOT_GROUP_ID, - } as IConnectionProfile; - - // Create mock connection node - const mockConnectionNode = new ConnectionNode(mockProfile); - - // Create mock data transfer - const mockDataTransfer = new vscode.DataTransfer(); - - // Mock ObjectExplorerUtils.getQualifiedName - const mockQualifiedName = "server1.db1"; - getQualifiedNameStub.returns(mockQualifiedName); - - // Call handleDrag - controller.handleDrag( - [mockConnectionNode], - mockDataTransfer, - {} as vscode.CancellationToken, - ); - - // Verify OE_MIME_TYPE data was set - const oeData = mockDataTransfer.get("application/vnd.code.tree.objectExplorer"); - expect(oeData, "OE_MIME_TYPE data should exist").to.exist; - expect(oeData.value, "OE data should match expected structure").to.deep.equal({ - name: mockConnectionNode.label.toString(), - type: "connection", - id: mockProfile.id, - isConnectionOrGroup: true, - }); - - // Verify TEXT_MIME_TYPE data was set - const textData = mockDataTransfer.get("text/plain"); - expect(textData, "TEXT_MIME_TYPE data should exist").to.exist; - expect(textData.value, "Text data should match qualified name").to.equal( - mockQualifiedName, - ); - }); - - test("should handle drag for ConnectionGroupNode", () => { - // Create mock connection group - const mockGroup: IConnectionGroup = { - id: "group1", - name: "Test Group", - parentId: TEST_ROOT_GROUP_ID, - description: "Test group description", - }; - - // Create mock connection group node - const mockGroupNode = new ConnectionGroupNode(mockGroup); - - // Create mock data transfer - const mockDataTransfer = new vscode.DataTransfer(); - - // Call handleDrag - controller.handleDrag( - [mockGroupNode], - mockDataTransfer, - {} as vscode.CancellationToken, - ); - - // Verify OE_MIME_TYPE data was set - const oeData = mockDataTransfer.get("application/vnd.code.tree.objectExplorer"); - expect(oeData, "OE_MIME_TYPE data should exist").to.exist; - expect(oeData.value, "OE data should match expected structure").to.deep.equal({ - name: mockGroupNode.label.toString(), - type: "connectionGroup", - id: mockGroup.id, - isConnectionOrGroup: true, - }); - - // Should NOT call getQualifiedName for ConnectionGroupNode - expect(getQualifiedNameStub.notCalled, "getQualifiedName should not be called").to.be - .true; - }); - - test("should handle drag for regular TreeNodeInfo with only TEXT_MIME_TYPE", () => { - // Create mock tree node info - const mockTreeNode = new TreeNodeInfo( - "testNode", - { - type: "table", - filterable: false, - hasFilters: false, - subType: "", - }, - vscode.TreeItemCollapsibleState.None, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - // Create mock data transfer - const mockDataTransfer = new vscode.DataTransfer(); - - // Mock ObjectExplorerUtils.getQualifiedName - const mockQualifiedName = "server1.db1.table1"; - getQualifiedNameStub.returns(mockQualifiedName); - - // Call handleDrag - controller.handleDrag([mockTreeNode], mockDataTransfer, {} as vscode.CancellationToken); - - // Verify OE_MIME_TYPE data was NOT set - const oeData = mockDataTransfer.get("application/vnd.code.tree.objectExplorer"); - expect(oeData, "OE_MIME_TYPE data should not exist").to.be.undefined; - - // Verify TEXT_MIME_TYPE data was set - const textData = mockDataTransfer.get("text/plain"); - expect(textData, "TEXT_MIME_TYPE data should exist").to.exist; - expect(textData.value, "Text data should match qualified name").to.equal( - mockQualifiedName, - ); - }); - }); - - suite("handleDrop", () => { - test("should handle drop of connection onto connection group successfully", async () => { - // Create mock connection profile - const mockProfile: IConnectionProfile = { - id: "conn1", - server: "server1", - database: "db1", - authenticationType: "Integrated", - user: "", - password: "", - savePassword: false, - groupId: "old-group-id", - } as IConnectionProfile; - - // Create mock connection group - const mockGroup: IConnectionGroup = { - id: "target-group-id", - name: "Target Group", - parentId: TEST_ROOT_GROUP_ID, - description: "Target group description", - }; - - // Create mock target group node - const mockTargetGroupNode = new ConnectionGroupNode(mockGroup); - - // Create mock data transfer with connection drag data - const mockDataTransfer = new vscode.DataTransfer(); - const dragData = { - name: "Test Connection", - type: "connection" as const, - id: mockProfile.id, - isConnectionOrGroup: true, - }; - mockDataTransfer.set( - "application/vnd.code.tree.objectExplorer", - new vscode.DataTransferItem(dragData), - ); - - // Mock connection store methods - (mockConnectionStore.connectionConfig.getConnectionById as sinon.SinonStub).resolves( - mockProfile, - ); - (mockConnectionStore.connectionConfig.updateConnection as sinon.SinonStub).resolves(); - - // Call handleDrop - await controller.handleDrop( - mockTargetGroupNode, - mockDataTransfer, - {} as vscode.CancellationToken, - ); - - expect( - (mockConnectionStore.connectionConfig.updateConnection as sinon.SinonStub) - .calledOnce, - "updateConnection should be called once", - ).to.be.true; - expect( - (mockConnectionStore.connectionConfig.updateConnection as sinon.SinonStub) - .args[0][0].groupId, - "Updated connection groupId should match target group id", - ).to.equal(mockGroup.id); - }); - - test("should handle drop of connection group onto another connection group successfully", async () => { - // Create mock connection group to be moved - const mockSourceGroup: IConnectionGroup = { - id: "source-group-id", - name: "Source Group", - parentId: "old-parent-id", - description: "Source group description", - }; - - // Create mock target connection group - const mockTargetGroup: IConnectionGroup = { - id: "target-group-id", - name: "Target Group", - parentId: TEST_ROOT_GROUP_ID, - description: "Target group description", - }; - - // Create mock target group node - const mockTargetGroupNode = new ConnectionGroupNode(mockTargetGroup); - - // Create mock data transfer with group drag data - const mockDataTransfer = new vscode.DataTransfer(); - const dragData = { - name: "Source Group", - type: "connectionGroup" as const, - id: mockSourceGroup.id, - isConnectionOrGroup: true, - }; - mockDataTransfer.set( - "application/vnd.code.tree.objectExplorer", - new vscode.DataTransferItem(dragData), - ); - - // Mock connection store methods - (mockConnectionStore.connectionConfig.getGroupById as sinon.SinonStub).returns( - mockSourceGroup, - ); - (mockConnectionStore.connectionConfig.updateGroup as sinon.SinonStub).resolves(); - - // Call handleDrop - await controller.handleDrop( - mockTargetGroupNode, - mockDataTransfer, - {} as vscode.CancellationToken, - ); - - // Verify group was retrieved and updated - expect( - (mockConnectionStore.connectionConfig.updateGroup as sinon.SinonStub).calledOnce, - "updateGroup should be called once", - ).to.be.true; - expect( - (mockConnectionStore.connectionConfig.updateGroup as sinon.SinonStub).args[0][0] - .parentId, - "Updated group parentId should match target group id", - ).to.equal(mockTargetGroup.id); - }); - - test("should handle drop onto root (undefined target) successfully", async () => { - // Create mock connection profile - const mockProfile: IConnectionProfile = { - id: "conn1", - server: "server1", - database: "db1", - authenticationType: "Integrated", - user: "", - password: "", - savePassword: false, - groupId: "old-group-id", - } as IConnectionProfile; - - // Create mock data transfer with connection drag data - const mockDataTransfer = new vscode.DataTransfer(); - const dragData = { - name: "Test Connection", - type: "connection" as const, - id: mockProfile.id, - isConnectionOrGroup: true, - }; - mockDataTransfer.set( - "application/vnd.code.tree.objectExplorer", - new vscode.DataTransferItem(dragData), - ); - - // Mock connection store methods - (mockConnectionStore.connectionConfig.getConnectionById as sinon.SinonStub).resolves( - mockProfile, - ); - (mockConnectionStore.connectionConfig.updateConnection as sinon.SinonStub).resolves(); - - // Call handleDrop with undefined target (root) - await controller.handleDrop( - undefined, - mockDataTransfer, - {} as vscode.CancellationToken, - ); - - // Verify connection was updated to root group - expect( - (mockConnectionStore.connectionConfig.updateConnection as sinon.SinonStub) - .calledOnce, - "updateConnection should be called once", - ).to.be.true; - expect( - (mockConnectionStore.connectionConfig.updateConnection as sinon.SinonStub) - .args[0][0].groupId, - "Updated connection groupId should match root group id", - ).to.equal(TEST_ROOT_GROUP_ID); - }); - - test("should prevent dropping group into itself", async () => { - // Create mock connection group - const mockGroup: IConnectionGroup = { - id: "group1", - name: "Test Group", - parentId: "old-parent-id", - description: "Test group description", - }; - - // Create mock group node (same group as source and target) - const mockGroupNode = new ConnectionGroupNode(mockGroup); - - // Create mock data transfer with group drag data - const mockDataTransfer = new vscode.DataTransfer(); - const dragData = { - name: "Test Group", - type: "connectionGroup" as const, - id: mockGroup.id, - isConnectionOrGroup: true, - }; - mockDataTransfer.set( - "application/vnd.code.tree.objectExplorer", - new vscode.DataTransferItem(dragData), - ); - - // Mock connection store methods - (mockConnectionStore.connectionConfig.getGroupById as sinon.SinonStub).returns( - mockGroup, - ); - - // Call handleDrop - await controller.handleDrop( - mockGroupNode, - mockDataTransfer, - {} as vscode.CancellationToken, - ); - - expect( - (mockConnectionStore.connectionConfig.updateGroup as sinon.SinonStub).called, - "updateGroup should not be called", - ).to.be.false; - }); - - test("should handle drop with invalid drag data gracefully", async () => { - // Create mock data transfer with invalid drag data - const mockDataTransfer = new vscode.DataTransfer(); - const invalidDragData = { - name: "Test Item", - isConnectionOrGroup: false, // Invalid: should be true for processing - }; - mockDataTransfer.set( - "application/vnd.code.tree.objectExplorer", - new vscode.DataTransferItem(invalidDragData), - ); - - // Create mock target group node - const mockTargetGroup: IConnectionGroup = { - id: "target-group-id", - name: "Target Group", - parentId: TEST_ROOT_GROUP_ID, - description: "Target group description", - }; - const mockTargetGroupNode = new ConnectionGroupNode(mockTargetGroup); - - // Call handleDrop - await controller.handleDrop( - mockTargetGroupNode, - mockDataTransfer, - {} as vscode.CancellationToken, - ); - - // Verify no processing occurred - expect( - (mockConnectionStore.connectionConfig.updateConnection as sinon.SinonStub).called, - "updateConnection should not be called", - ).to.be.false; - expect( - (mockConnectionStore.connectionConfig.updateGroup as sinon.SinonStub).called, - "updateGroup should not be called", - ).to.be.false; - }); - - test("should handle drop with missing drag data gracefully", async () => { - // Create mock data transfer with no OE_MIME_TYPE data - const mockDataTransfer = new vscode.DataTransfer(); - - // Create mock target group node - const mockTargetGroup: IConnectionGroup = { - id: "target-group-id", - name: "Target Group", - parentId: TEST_ROOT_GROUP_ID, - description: "Target group description", - }; - const mockTargetGroupNode = new ConnectionGroupNode(mockTargetGroup); - - // Call handleDrop - await controller.handleDrop( - mockTargetGroupNode, - mockDataTransfer, - {} as vscode.CancellationToken, - ); - - // Verify no processing occurred - expect( - (mockConnectionStore.connectionConfig.updateConnection as sinon.SinonStub).called, - "updateConnection should not be called", - ).to.be.false; - expect( - (mockConnectionStore.connectionConfig.updateGroup as sinon.SinonStub).called, - "updateGroup should not be called", - ).to.be.false; - }); - - test("should handle drop with non-connection/group target gracefully", async () => { - // Create mock connection profile - const mockProfile: IConnectionProfile = { - id: "conn1", - server: "server1", - database: "db1", - authenticationType: "Integrated", - user: "", - password: "", - savePassword: false, - groupId: "old-group-id", - } as IConnectionProfile; - - // Create mock data transfer with connection drag data - const mockDataTransfer = new vscode.DataTransfer(); - const dragData = { - name: "Test Connection", - type: "connection" as const, - id: mockProfile.id, - isConnectionOrGroup: true, - }; - mockDataTransfer.set( - "application/vnd.code.tree.objectExplorer", - new vscode.DataTransferItem(dragData), - ); - - // Create mock regular tree node as target (not a connection or group) - const mockTargetNode = new TreeNodeInfo( - "targetNode", - { - type: "table", - filterable: false, - hasFilters: false, - subType: "", - }, - vscode.TreeItemCollapsibleState.None, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - ); - - // Call handleDrop - await controller.handleDrop( - mockTargetNode, - mockDataTransfer, - {} as vscode.CancellationToken, - ); - - // Verify nothing was moved - expect( - (mockConnectionStore.connectionConfig.updateConnection as sinon.SinonStub).called, - "updateConnection should not be called", - ).to.be.false; - expect( - (mockConnectionStore.connectionConfig.updateGroup as sinon.SinonStub).called, - "updateGroup should not be called", - ).to.be.false; - }); - }); -}); From 14ed174553b7002e6dd0f33a86576fb96306d2d5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 7 Jul 2025 20:24:28 +0000 Subject: [PATCH 5/5] Changes before error encountered Co-authored-by: Benjin <1609827+Benjin@users.noreply.github.com> --- test/unit/connectionStore.test.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/unit/connectionStore.test.ts b/test/unit/connectionStore.test.ts index 5a6f562913..4ad84054bb 100644 --- a/test/unit/connectionStore.test.ts +++ b/test/unit/connectionStore.test.ts @@ -51,7 +51,13 @@ suite("ConnectionStore Tests", () => { return Promise.resolve(); }, }; - sandbox.stub(mockConnectionConfig, "initialized").get(() => resolvedDeferred); + + // Use Object.defineProperty to define the initialized property on the mock instance + Object.defineProperty(mockConnectionConfig, 'initialized', { + get: () => resolvedDeferred, + enumerable: true, + configurable: true + }); }); teardown(() => {