diff --git a/.vscode/launch.json b/.vscode/launch.json index b1fbaf5..17ee04f 100755 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -19,16 +19,13 @@ "preLaunchTask": "${defaultBuildTask}" }, { - "name": "Extension Tests", - "type": "extensionHost", + "name": "Run Tests", + "type": "node", "request": "launch", - "runtimeExecutable": "${execPath}", + "program": "${workspaceFolder}/node_modules/.bin/extest", "args": [ - "--extensionDevelopmentPath=${workspaceFolder}", - "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" - ], - "outFiles": [ - "${workspaceFolder}/out/test/**/*.js" + "setup-and-run", + "out/test/ui-test/*.test.js -m ./mocharc.js" ], "preLaunchTask": "${defaultBuildTask}" } diff --git a/README.md b/README.md index e622305..e044900 100755 --- a/README.md +++ b/README.md @@ -17,9 +17,6 @@ For file name presets: - CLASSNAMELOWER - default classname to lower - CLASSNAMECAPI - default classname with capitalized first letter - CLASSNAME - default classname -- CURRENTDATETIME - current date and time -- CURRENTDATE - current date -- CURRENTTIME - current time For file content presets: diff --git a/mocharc.js b/mocharc.js new file mode 100644 index 0000000..f83eff8 --- /dev/null +++ b/mocharc.js @@ -0,0 +1,5 @@ +"use strict"; + +module.exports = { + timeout: 60000, +}; \ No newline at end of file diff --git a/package.json b/package.json index cb857ad..638415e 100755 --- a/package.json +++ b/package.json @@ -77,12 +77,12 @@ "cpp.creator.sourceFileNamePreset": { "type": "string", "default": "{{*CLASSNAME*}}.cpp", - "description": "Name of your source file. \nAvailable commands are:\n{{*CLASSNAME*}} - entered classname.\n{{*CLASSNAMEUPPER*}} - entered classname in upper-case letters.\n{{*CLASSNAMELOWER*}} - entered classname in lower-case letters.\n{{*CURRENTDATETIME*}} - current date and time.\n{{*CURRENTDATE*}} - current date.\n{{*CURRENTTIME*}} - current time." + "description": "Name of your source file. \nAvailable commands are:\n{{*CLASSNAME*}} - entered classname.\n{{*CLASSNAMEUPPER*}} - entered classname in upper-case letters.\n{{*CLASSNAMELOWER*}} - entered classname in lower-case letters." }, "cpp.creator.headerFileNamePreset": { "type": "string", "default": "{{*CLASSNAME*}}.h", - "description": "Name of your header file. \nAvailable commands are:\n{{*CLASSNAME*}} - entered classname.\n{{*CLASSNAMEUPPER*}} - entered classname in upper-case letters.\n{{*CLASSNAMELOWER*}} - entered classname in lower-case letters.\n{{*CURRENTDATETIME*}} - current date and time.\n{{*CURRENTDATE*}} - current date.\n{{*CURRENTTIME*}} - current time." + "description": "Name of your header file. \nAvailable commands are:\n{{*CLASSNAME*}} - entered classname.\n{{*CLASSNAMEUPPER*}} - entered classname in upper-case letters.\n{{*CLASSNAMELOWER*}} - entered classname in lower-case letters." }, "cpp.creator.createFolder": { "type": "boolean", @@ -98,7 +98,10 @@ "compile": "tsc -p ./", "watch": "tsc -watch -p ./", "pretest": "npm run compile", - "test": "extest setup-and-run out/test/ui-test/*.test.js" + "test": "extest setup-and-run out/test/ui-test/*.test.js -m ./mocharc.js", + "test:file-name-replacement": "extest setup-and-run out/test/ui-test/file-name-replacement.test.js -m ./mocharc.js", + "test:file-content-replacement": "extest setup-and-run out/test/ui-test/file-content-replacement.test.js -m ./mocharc.js", + "test:negative": "extest setup-and-run out/test/ui-test/negative.test.js -m ./mocharc.js" }, "devDependencies": { "@types/glob": "^7.1.1", diff --git a/src/class_creator.ts b/src/class_creator.ts index 636c681..f09352e 100644 --- a/src/class_creator.ts +++ b/src/class_creator.ts @@ -43,9 +43,6 @@ export class class_creator { reg_expression: lower_regex, replace_string: regex_commands.lower_case(this.class_name)},// CLASSNAMELOWER - default classname to lower { reg_expression: cap_regex, replace_string: regex_commands.capitalize(this.class_name)}, // CLASSNAMECAPI - default classname with capitalized first letter { reg_expression: default_regex, replace_string: regex_commands.default(this.class_name)}, // CLASSNAME - default classname - { reg_expression: datetime_regex, replace_string: regex_commands.current_date_time()}, // CURRENTDATETIME - the current date and time - { reg_expression: date_regex, replace_string: regex_commands.current_date()}, // CURRENTDATE - the current date - { reg_expression: time_regex, replace_string: regex_commands.current_time()}, // CURRENTTIME - the current time ] const content_cmds: Array = [ diff --git a/src/extension.ts b/src/extension.ts index 24c8931..6089da3 100755 --- a/src/extension.ts +++ b/src/extension.ts @@ -36,11 +36,11 @@ export async function activate(context: vscode.ExtensionContext) { //Create the class there if (out) { - vscode.window.showInformationMessage('Your Class ' + res + ' has been created! \n(@'+dir_h.dir()+')'); + vscode.window.showInformationMessage('Your class "' + res + '" has been created! \n(@'+dir_h.dir()+')'); } else { - vscode.window.showErrorMessage('Your Class ' + res + ' has been not created! \n(@'+dir_h.dir()+')'); + vscode.window.showErrorMessage('Your class "' + res + '" has NOT been created! \n(@'+dir_h.dir()+')'); } }); // Display a message box to the user diff --git a/src/test/ui-test/activation.test.ts b/src/test/ui-test/activation.test.ts index ef59b32..65dbf7a 100644 --- a/src/test/ui-test/activation.test.ts +++ b/src/test/ui-test/activation.test.ts @@ -1,22 +1,49 @@ -import { assert } from 'console'; -import { VSBrowser, WebDriver } from 'vscode-extension-tester'; +import { VSController } from './utils/vs-controller'; +import { EditorView } from 'vscode-extension-tester'; +import { CppCreatorExtHelper } from './utils/extension-helper'; +import { ClassHelper } from './utils/class-helper'; +import * as assert from "assert"; +import * as fs from "fs"; describe('Activation test suite', () => { - let browser: VSBrowser; - let driver: WebDriver; + const workSpaceDir = "/tmp/cppWs"; + let vsController = new VSController(); + let cppCreatorExt = new CppCreatorExtHelper(); before(async () => { - browser = VSBrowser.instance; - driver = browser.driver; + await vsController.openWorkspace(workSpaceDir); }); + after(async ()=>{ + }) + it('Extension can be activated by "Alt+X"', async () => { - console.log("here2"); - // Your test logic for Alt+X activation - }); + await vsController.openNewEmptyEditor(); + + const className = "testClass"; + await cppCreatorExt.openExtPromptByShortcut(className); + + assert(await ClassHelper.fileExistsWithContent(className, workSpaceDir+"/"+className+".h", ClassHelper.defaultHeaderContent(className), true)); + assert(await ClassHelper.fileExistsWithContent(className, workSpaceDir+"/"+className+".cpp", ClassHelper.defaultClassContent(className), true)); + + await new EditorView().closeAllEditors(); + }) it('Extension can be activated by the context menu', async () => { - console.log("here"); - // Your test logic for context menu activation + // test logic for context menu activ. + + const className = "testClass"; + await cppCreatorExt.openExtPromptByContextMenu(className, workSpaceDir); + + assert(await ClassHelper.fileExistsWithContent(className, workSpaceDir+"/"+className+".h", ClassHelper.defaultHeaderContent(className), true)); + assert(await ClassHelper.fileExistsWithContent(className, workSpaceDir+"/"+className+".cpp", ClassHelper.defaultClassContent(className), true)); + }) + + it('Extension can be activated by the command pallette', async () => { + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + assert(await ClassHelper.fileExistsWithContent(className, workSpaceDir+"/"+className+".h", ClassHelper.defaultHeaderContent(className), true)); + assert(await ClassHelper.fileExistsWithContent(className, workSpaceDir+"/"+className+".cpp", ClassHelper.defaultClassContent(className), true)); }); -}); +}) diff --git a/src/test/ui-test/file-content-replacement.test.ts b/src/test/ui-test/file-content-replacement.test.ts new file mode 100644 index 0000000..08325e9 --- /dev/null +++ b/src/test/ui-test/file-content-replacement.test.ts @@ -0,0 +1,381 @@ +import { VSController } from './utils/vs-controller'; +import { CppCreatorExtHelper } from './utils/extension-helper'; +import { ClassHelper } from './utils/class-helper'; +import * as assert from "assert"; +import * as fs from "fs"; +import { ExtensionSettings } from './utils/extension-settings-helper'; + +describe('File-content replacement test suite', () => { + const workSpaceDir = "/tmp/cppWs"; + let vsController = new VSController(); + let cppCreatorExt = new CppCreatorExtHelper(); + let ext_settings = new ExtensionSettings(); + + let defaultSourceContentPreset = ""; + let defaultHeaderContentPreset = ""; + + before(async () => { + await vsController.openWorkspace(workSpaceDir); + + defaultSourceContentPreset = await ext_settings.getSourceFileContentPreset(); + defaultHeaderContentPreset = await ext_settings.getHeaderFileContentPreset(); + assert (defaultHeaderContentPreset != "" && defaultSourceContentPreset != ""); + }); + + after(async ()=>{ + await ext_settings.setHeaderFileContentPreset(defaultHeaderContentPreset) + await ext_settings.setSourceFileContentPreset(defaultSourceContentPreset); + }) + + afterEach(async ()=>{ + // just delete the directory + let dirContents = fs.readdirSync(workSpaceDir); + for(let contentPath of dirContents) + { + try + { + fs.unlinkSync(workSpaceDir+"/"+contentPath); + } catch(e) + { + } + + } + + }) + + beforeEach(async ()=>{ + }) + + // header file content tests: + it('[header file content] - HEADERFILENAME multiple', async () => { + + await ext_settings.setHeaderFileContentPreset("{{*HEADERFILENAME*}}-{{*HEADERFILENAME*}}"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const fileName = className + ".h"; + const path = workSpaceDir + "/" + fileName; + const expectedContent = fileName+"-"+fileName; + + assert(await ClassHelper.fileExistsWithContent(className, path, expectedContent, false)); + }) + + it('[header file content] - HEADERFILENAME once', async () => { + + await ext_settings.setHeaderFileContentPreset("{{*HEADERFILENAME*}}"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const fileName = className + ".h"; + const path = workSpaceDir + "/" + fileName; + const expectedContent = fileName; + + assert(await ClassHelper.fileExistsWithContent(className, path, expectedContent, false)); + }) + + it('[header file content] - SOURCEFILENAME once', async () => { + await ext_settings.setHeaderFileContentPreset("{{*SOURCEFILENAME*}}"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const fileName = className + ".h"; + const path = workSpaceDir + "/" + fileName; + const expectedContent = fileName.replace(".h", ".cpp"); + + assert(await ClassHelper.fileExistsWithContent(className, path, expectedContent, false)); + }) + + it('[header file content] - CLASSNAMEUPPER once', async () => { + await ext_settings.setHeaderFileContentPreset("{{*CLASSNAMEUPPER*}}"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const fileName = className + ".h"; + const path = workSpaceDir + "/" + fileName; + const expectedContent = className.toUpperCase(); + + assert(await ClassHelper.fileExistsWithContent(className, path, expectedContent, false)); + }) + + it('[header file content] - CLASSNAMELOWER once', async () => { + await ext_settings.setHeaderFileContentPreset("{{*CLASSNAMELOWER*}}"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const fileName = className + ".h"; + const path = workSpaceDir + "/" + fileName; + const expectedContent = className.toLowerCase(); + + assert(await ClassHelper.fileExistsWithContent(className, path, expectedContent, false)); + }) + + it('[header file content] - CLASSNAMECAPI once', async () => { + await ext_settings.setHeaderFileContentPreset("{{*CLASSNAMECAPI*}}"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const fileName = className + ".h"; + const path = workSpaceDir + "/" + fileName; + const expectedContent = className[0].toUpperCase() + className.substring(1); + + assert(await ClassHelper.fileExistsWithContent(className, path, expectedContent, false)); + }) + + it('[header file content] - CLASSNAME once', async () => { + await ext_settings.setHeaderFileContentPreset("{{*CLASSNAME*}}"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const fileName = className + ".h"; + const path = workSpaceDir + "/" + fileName; + const expectedContent = className + + assert(await ClassHelper.fileExistsWithContent(className, path, expectedContent, false)); + }) + + it('[header file content] - CURRENTDATETIME once', async () => { + await ext_settings.setHeaderFileContentPreset("{{*CURRENTDATETIME*}}"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const currentDateTimeString = new Date().toLocaleString(); + + const fileName = className + ".h"; + const path = workSpaceDir + "/" + fileName; + + const content = await ClassHelper.fileExistsGetContent(path, className); + + try + { + assert(content == currentDateTimeString); + } catch(e) + { + const diff = Math.abs(new Date(content).getTime() - new Date(currentDateTimeString).getTime()); + console.log("time diff", diff); + assert(diff < 1000); + } + + }) + + it('[header file content] - CURRENTDATE once', async () => { + await ext_settings.setHeaderFileContentPreset("{{*CURRENTDATE*}}"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const currentDateString = new Date().toLocaleDateString(); + + const fileName = className + ".h"; + const path = workSpaceDir + "/" + fileName; + + const content = await ClassHelper.fileExistsGetContent(path, className); + + assert(content == currentDateString); + }) + + it('[header file content] - CURRENTTIME once', async () => { + await ext_settings.setHeaderFileContentPreset("{{*CURRENTTIME*}}"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const currentTimeString = new Date().toLocaleTimeString(); + + const fileName = className + ".h"; + const path = workSpaceDir + "/" + fileName; + + const content = await ClassHelper.fileExistsGetContent(path, className); + + const trimmedContent = content.trim().replace(/\u{2007}/gu, ' ').replace(/\u{202F}/gu, ' '); + const trimmedCurrentTimeString = currentTimeString.trim().replace(/\u{2007}/gu, ' ').replace(/\u{202F}/gu, ' '); + + assert(trimmedContent == trimmedCurrentTimeString); + }) + + it('[header file content] - combination', async () => { + + await ext_settings.setHeaderFileContentPreset("{{*CLASSNAMECAPI*}}-{{*CLASSNAME*}}-{{*HEADERFILENAME*}}"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const fileName = className + ".h"; + const path = workSpaceDir + "/" + fileName; + const capitalized = className[0].toUpperCase() + className.substring(1); + const expectedContent = capitalized + "-"+className+"-"+fileName; + + assert(await ClassHelper.fileExistsWithContent(className, path, expectedContent, false)); + }) + + // source file content tests: + it('[source file content] - HEADERFILENAME multiple', async () => { + await ext_settings.setSourceFileContentPreset("{{*HEADERFILENAME*}}-{{*HEADERFILENAME*}}"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const fileName = className + ".cpp"; + const path = workSpaceDir + "/" + fileName; + const expectedContent = fileName.replace(".cpp", ".h")+"-"+fileName.replace(".cpp", ".h"); + + assert(await ClassHelper.fileExistsWithContent(className, path, expectedContent, false)); + }) + + it('[source file content] - HEADERFILENAME once', async () => { + await ext_settings.setSourceFileContentPreset("{{*HEADERFILENAME*}}"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const fileName = className + ".cpp"; + const path = workSpaceDir + "/" + fileName; + const expectedContent = fileName.replace(".cpp", ".h"); + + assert(await ClassHelper.fileExistsWithContent(className, path, expectedContent, false)); + }) + + it('[source file content] - SOURCEFILENAME once', async () => { + await ext_settings.setSourceFileContentPreset("{{*SOURCEFILENAME*}}"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const fileName = className + ".cpp"; + const path = workSpaceDir + "/" + fileName; + const expectedContent = fileName; + + assert(await ClassHelper.fileExistsWithContent(className, path, expectedContent, false)); + }) + + it('[source file content] - CLASSNAMEUPPER once', async () => { + await ext_settings.setSourceFileContentPreset("{{*CLASSNAMEUPPER*}}"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const fileName = className + ".cpp"; + const path = workSpaceDir + "/" + fileName; + const expectedContent = className.toUpperCase(); + + assert(await ClassHelper.fileExistsWithContent(className, path, expectedContent, false)); + }) + + it('[source file content] - CLASSNAMELOWER once', async () => { + await ext_settings.setSourceFileContentPreset("{{*CLASSNAMELOWER*}}"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const fileName = className + ".cpp"; + const path = workSpaceDir + "/" + fileName; + const expectedContent = className.toLowerCase(); + + assert(await ClassHelper.fileExistsWithContent(className, path, expectedContent, false)); + }) + + it('[source file content] - CLASSNAMECAPI once', async () => { + await ext_settings.setSourceFileContentPreset("{{*CLASSNAMECAPI*}}"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const fileName = className + ".cpp"; + const path = workSpaceDir + "/" + fileName; + const expectedContent = className[0].toUpperCase() + className.substring(1); + + assert(await ClassHelper.fileExistsWithContent(className, path, expectedContent, false)); + }) + + it('[source file content] - CLASSNAME once', async () => { + await ext_settings.setSourceFileContentPreset("{{*CLASSNAME*}}"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const fileName = className + ".cpp"; + const path = workSpaceDir + "/" + fileName; + const expectedContent = className; + + assert(await ClassHelper.fileExistsWithContent(className, path, expectedContent, false)); + }) + + it('[source file content] - CURRENTDATETIME once', async () => { + await ext_settings.setSourceFileContentPreset("{{*CURRENTDATETIME*}}"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const currentDateTimeString = new Date().toLocaleString(); + + const fileName = className + ".cpp"; + const path = workSpaceDir + "/" + fileName; + + const content = await ClassHelper.fileExistsGetContent(path, className); + + try + { + assert(content == currentDateTimeString); + } catch(e) + { + assert(Math.abs(new Date(content).getTime() - new Date(currentDateTimeString).getTime()) < 10); + } + + }) + + it('[source file content] - CURRENTDATE once', async () => { + await ext_settings.setSourceFileContentPreset("{{*CURRENTDATE*}}"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const currentDateString = new Date().toLocaleDateString(); + + const fileName = className + ".cpp"; + const path = workSpaceDir + "/" + fileName; + + const content = await ClassHelper.fileExistsGetContent(path, className); + + assert(content == currentDateString); + }) + + it('[source file content] - CURRENTTIME once', async () => { + await ext_settings.setSourceFileContentPreset("{{*CURRENTTIME*}}"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const currentTimeString = new Date().toLocaleTimeString(); + + const fileName = className + ".cpp"; + const path = workSpaceDir + "/" + fileName; + + const content = await ClassHelper.fileExistsGetContent(path, className); + const trimmedContent = content.trim().replace(/\u{2007}/gu, ' ').replace(/\u{202F}/gu, ' '); + const trimmedCurrentTimeString = currentTimeString.trim().replace(/\u{2007}/gu, ' ').replace(/\u{202F}/gu, ' '); + + assert(trimmedContent == trimmedCurrentTimeString); + }) + + it('[source file content] - combination', async () => { + + await ext_settings.setSourceFileContentPreset("{{*CLASSNAMECAPI*}}-{{*CLASSNAME*}}-{{*SOURCEFILENAME*}}"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const fileName = className + ".cpp"; + const path = workSpaceDir + "/" + fileName; + const capitalized = className[0].toUpperCase() + className.substring(1); + const expectedContent = capitalized + "-"+className+"-"+fileName; + + assert(await ClassHelper.fileExistsWithContent(className, path, expectedContent, false)) + }) +}); \ No newline at end of file diff --git a/src/test/ui-test/file-creation.test.ts b/src/test/ui-test/file-creation.test.ts index e69de29..389cd13 100644 --- a/src/test/ui-test/file-creation.test.ts +++ b/src/test/ui-test/file-creation.test.ts @@ -0,0 +1,161 @@ +import { CppCreatorExtHelper } from "./utils/extension-helper"; +import { VSController } from "./utils/vs-controller"; +import { ExtensionSettings } from "./utils/extension-settings-helper"; +import * as assert from "assert"; +import * as fs from "fs"; +import { ClassHelper } from "./utils/class-helper"; + +describe('Creation test suite', () => { + const workSpaceDir = "/tmp/cppWs"; + let vsController = new VSController(); + let cppCreatorExt = new CppCreatorExtHelper(); + let ext_settings = new ExtensionSettings(); + + before(async () => { + await vsController.openWorkspace(workSpaceDir); + }); + + after(async ()=>{ + + }) + + afterEach(async ()=>{ + await ext_settings.setSetPath(undefined); + await ext_settings.setCreateFolder(false); + }); + + it("Don't create new folder if 'Create Folder' is false", async ()=>{ + assert(await ext_settings.isCreateFolderEnabled() == false) + + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + assert(await ClassHelper.fileExistsWithContent(className, workSpaceDir+"/"+className+".h", ClassHelper.defaultHeaderContent(className), true)); + assert(await ClassHelper.fileExistsWithContent(className, workSpaceDir+"/"+className+".cpp", ClassHelper.defaultClassContent(className), true)); + }); + + it("Create new folder if 'Create Folder' is true", async ()=>{ + assert(await ext_settings.isCreateFolderEnabled() == false) + + await ext_settings.setCreateFolder(true); + + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + assert(await ClassHelper.fileExistsWithContent(className, workSpaceDir+"/"+className+"/"+className+".h", ClassHelper.defaultHeaderContent(className), true)); + assert(await ClassHelper.fileExistsWithContent(className, workSpaceDir+"/"+className+"/"+className+".cpp", ClassHelper.defaultClassContent(className), true)); + + const folderPath = workSpaceDir+"/"+className; + // Check for empty folder + const readDirContent = fs.readdirSync(folderPath); + assert(readDirContent.length == 0); + + fs.rmdirSync(folderPath); + }); + + it("Prompt for the path if 'SetPath' is true", async ()=> + { + assert(await ext_settings.isSetPath() == undefined) + + let newPath = "/tmp/newWsPath"; + + await ext_settings.setSetPath(true); + + const className = "testClass"; + + await cppCreatorExt.openExtPromptWithPathPromptByCmdPallette(className, newPath); + assert(await ClassHelper.fileExistsWithContent(className, newPath+"/"+className+".h", ClassHelper.defaultHeaderContent(className), true)); + assert(await ClassHelper.fileExistsWithContent(className, newPath+"/"+className+".cpp", ClassHelper.defaultClassContent(className), true)); + + // ClassHelper deletes the checked files. + let newWorkSpaceContent = fs.readdirSync(newPath); + assert(newWorkSpaceContent.length == 0); + }); + + it("Don't prompt for the path if 'SetPath' is false", async ()=> + { + await ext_settings.setSetPath(false); + + assert(await ext_settings.isCreateFolderEnabled() == false) + + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + assert(await ClassHelper.fileExistsWithContent(className, workSpaceDir+"/"+className+".h", ClassHelper.defaultHeaderContent(className), true)); + assert(await ClassHelper.fileExistsWithContent(className, workSpaceDir+"/"+className+".cpp", ClassHelper.defaultClassContent(className), true)); + }); + + it("Don't prompt for the path if 'SetPath' is undefined", async ()=>{ + await ext_settings.setSetPath(undefined); + + assert(await ext_settings.isCreateFolderEnabled() == false) + + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + assert(await ClassHelper.fileExistsWithContent(className, workSpaceDir+"/"+className+".h", ClassHelper.defaultHeaderContent(className), true)); + assert(await ClassHelper.fileExistsWithContent(className, workSpaceDir+"/"+className+".cpp", ClassHelper.defaultClassContent(className), true)); + }); + + it("Don't prompt for the path if 'SetPath' is a string with the wished path", async ()=>{ + let newPath = "/tmp/newWsPath"; + + await ext_settings.setSetPath(newPath); + + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + assert(await ClassHelper.fileExistsWithContent(className, newPath+"/"+className+".h", ClassHelper.defaultHeaderContent(className), true)); + assert(await ClassHelper.fileExistsWithContent(className, newPath+"/"+className+".cpp", ClassHelper.defaultClassContent(className), true)); + + // ClassHelper deletes the checked files. + let newWorkSpaceContent = fs.readdirSync(newPath); + assert(newWorkSpaceContent.length == 0); + }); + + it("'SetPath' is overriden by context-menu location", async()=>{ + await ext_settings.setSetPath(true) + assert(await ext_settings.isSetPath() == true) + + const className = "testClass"; + const expDir = workSpaceDir + "/child"; + await cppCreatorExt.openExtPromptByContextMenuWithChild(className, workSpaceDir, "child"); + assert(await ClassHelper.fileExistsWithContent(className, expDir+"/"+className+".h", ClassHelper.defaultHeaderContent(className), true)); + assert(await ClassHelper.fileExistsWithContent(className, expDir+"/"+className+".cpp", ClassHelper.defaultClassContent(className), true)); + + let newWorkSpaceContent = fs.readdirSync(expDir); + assert(newWorkSpaceContent.length == 0); + }); + + it("Combine 'createFolder' with 'setPath' ('createFolder' ignored)", async()=>{ + await ext_settings.setCreateFolder(true) + + let newPath = "/tmp/newWsPath"; + + await ext_settings.setSetPath(newPath); + + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + assert(await ClassHelper.fileExistsWithContent(className, newPath+"/"+className+".h", ClassHelper.defaultHeaderContent(className), true)); + assert(await ClassHelper.fileExistsWithContent(className, newPath+"/"+className+".cpp", ClassHelper.defaultClassContent(className), true)); + + // ClassHelper deletes the checked files. + let newWorkSpaceContent = fs.readdirSync(newPath); + assert(newWorkSpaceContent.length == 0); + + }); + + it("Combine 'createFolder' with context-menu location ('createFolder' ignored)", async ()=>{ + await ext_settings.setCreateFolder(true) + + const className = "testClass"; + const expDir = workSpaceDir + "/child"; + await cppCreatorExt.openExtPromptByContextMenuWithChild(className, workSpaceDir, "child"); + assert(await ClassHelper.fileExistsWithContent(className, expDir+"/"+className+".h", ClassHelper.defaultHeaderContent(className), true)); + assert(await ClassHelper.fileExistsWithContent(className, expDir+"/"+className+".cpp", ClassHelper.defaultClassContent(className), true)); + + let newWorkSpaceContent = fs.readdirSync(expDir); + assert(newWorkSpaceContent.length == 0); + }); +}); \ No newline at end of file diff --git a/src/test/ui-test/file-name-replacement.test.ts b/src/test/ui-test/file-name-replacement.test.ts new file mode 100644 index 0000000..3f6f525 --- /dev/null +++ b/src/test/ui-test/file-name-replacement.test.ts @@ -0,0 +1,203 @@ +import { VSController } from './utils/vs-controller'; +import { CppCreatorExtHelper } from './utils/extension-helper'; +import { ClassHelper } from './utils/class-helper'; +import * as assert from "assert"; +import * as fs from "fs"; +import { ExtensionSettings } from './utils/extension-settings-helper'; + +describe('File-name replacement test suite', () => { + const workSpaceDir = "/tmp/cppWs"; + let vsController = new VSController(); + let cppCreatorExt = new CppCreatorExtHelper(); + let ext_settings = new ExtensionSettings(); + + let defaultHeaderFileNamePreset = ""; + let defaultSourceFileNamePreset = ""; + + before(async () => { + await vsController.openWorkspace(workSpaceDir); + + defaultHeaderFileNamePreset = await ext_settings.getHeaderFileNamePreset(); + defaultSourceFileNamePreset = await ext_settings.getSourceFileNamePreset(); + assert (defaultHeaderFileNamePreset != "" && defaultSourceFileNamePreset != ""); + }); + + after(async ()=>{ + await ext_settings.setSourceFileNamePreset(defaultSourceFileNamePreset); + await ext_settings.setHeaderFileNamePreset(defaultHeaderFileNamePreset); + }) + + afterEach(async ()=>{ + // just delete the directory + let dirContents = fs.readdirSync(workSpaceDir); + for(let contentPath of dirContents) + { + try + { + fs.unlinkSync(workSpaceDir+"/"+contentPath); + } catch(e) + { + } + + } + + }) + + beforeEach(async ()=>{ + }) + + // header file name tests: + it('[header file name] - CLASSNAMEUPPER multiple', async () => { + + await ext_settings.setHeaderFileNamePreset("{{*CLASSNAMEUPPER*}}-{{*CLASSNAMEUPPER*}}.h"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const path = workSpaceDir + "/" + className.toUpperCase()+"-"+ className.toUpperCase() + ".h"; + assert(await ClassHelper.fileExists(path)); + }) + + it('[header file name] - CLASSNAMEUPPER once', async () => { + await ext_settings.setHeaderFileNamePreset("{{*CLASSNAMEUPPER*}}.h"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const path = workSpaceDir + "/" + className.toUpperCase() + ".h"; + assert(await ClassHelper.fileExists(path)); + }) + + it('[header file name] - CLASSNAMELOWER once', async () => { + await ext_settings.setHeaderFileNamePreset("{{*CLASSNAMELOWER*}}.h"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const path = workSpaceDir + "/" + className.toLowerCase() + ".h"; + assert(await ClassHelper.fileExists(path)); + }) + + it('[header file name] - CLASSNAMECAPI once', async () => { + await ext_settings.setHeaderFileNamePreset("{{*CLASSNAMECAPI*}}.h"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const capitalized = className[0].toUpperCase() + className.substring(1); + + const path = workSpaceDir + "/" + capitalized + ".h"; + assert(await ClassHelper.fileExists(path)); + }) + + it('[header file name] - CLASSNAME once', async () => { + await ext_settings.setHeaderFileNamePreset("{{*CLASSNAME*}}.h"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const path = workSpaceDir + "/" + className + ".h"; + assert(await ClassHelper.fileExists(path)); + }) + + /* it('[header file name] - CURRENTDATETIME once', async () => { + await ext_settings.setHeaderFileNamePreset("{{*CURRENTDATETIME*}}.h"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const currentDateTimeString = new Date().toLocaleString(); + const headerPaths = await waitUntilFileWithEndingCreated(".h", workSpaceDir); + assert(headerPaths.length == 1); + + let createdDateTime = headerPaths[0].replace(".h", ""); + + console.log(currentDateTimeString); + console.log(createdDateTime); + }) + + it('[header file name] - CURRENTDATE once', async () => { + + }) + + it('[header file name] - CURRENTTIME once', async () => { + + })*/ + + it('[header file name] - combination', async () => { + await ext_settings.setHeaderFileNamePreset("{{*CLASSNAMECAPI*}}-{{*CLASSNAME*}}-{{*CLASSNAMEUPPER*}}.h"); + const className = "sImple"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const capitalized = className[0].toUpperCase() + className.substring(1); + + const path = workSpaceDir + "/" + capitalized +"-"+className+"-"+ className.toUpperCase()+ ".h"; + assert(await ClassHelper.fileExists(path)); + }) + + // source file name tests: + it('[source file name] - CLASSNAMEUPPER multiple', async () => { + await ext_settings.setSourceFileNamePreset("{{*CLASSNAMEUPPER*}}-{{*CLASSNAMEUPPER*}}.cpp"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const path = workSpaceDir + "/" + className.toUpperCase()+"-"+ className.toUpperCase() + ".cpp"; + assert(await ClassHelper.fileExists(path)); + }) + + it('[source file name] - CLASSNAMEUPPER once', async () => { + await ext_settings.setSourceFileNamePreset("{{*CLASSNAMEUPPER*}}.cpp"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const path = workSpaceDir + "/" + className.toUpperCase() + ".cpp"; + assert(await ClassHelper.fileExists(path)); + }) + + it('[source file name] - CLASSNAMECAPI once', async () => { + await ext_settings.setSourceFileNamePreset("{{*CLASSNAMECAPI*}}.cpp"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const capitalized = className[0].toUpperCase() + className.substring(1); + + const path = workSpaceDir + "/" + capitalized + ".cpp"; + assert(await ClassHelper.fileExists(path)); + }) + + it('[source file name] - CLASSNAME once', async () => { + await ext_settings.setSourceFileNamePreset("{{*CLASSNAME*}}.cpp"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const path = workSpaceDir + "/" + className + ".cpp"; + assert(await ClassHelper.fileExists(path)); + }) + + it('[source file name] - CLASSNAMELOWER once', async () => { + await ext_settings.setSourceFileNamePreset("{{*CLASSNAMELOWER*}}.cpp"); + const className = "testClass"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const path = workSpaceDir + "/" + className.toLowerCase() + ".cpp"; + assert(await ClassHelper.fileExists(path)); + }) + + it('[source file name] - combination', async () => { + await ext_settings.setSourceFileNamePreset("{{*CLASSNAMECAPI*}}-{{*CLASSNAME*}}-{{*CLASSNAMEUPPER*}}.cpp"); + const className = "sImple"; + + await cppCreatorExt.openExtPromptByCmdPallette(className); + + const capitalized = className[0].toUpperCase() + className.substring(1); + + const path = workSpaceDir + "/" + capitalized +"-"+className+"-"+ className.toUpperCase()+ ".cpp"; + assert(await ClassHelper.fileExists(path)); + }) +}); \ No newline at end of file diff --git a/src/test/ui-test/init.test.ts b/src/test/ui-test/init.test.ts index a3b41d0..156faca 100644 --- a/src/test/ui-test/init.test.ts +++ b/src/test/ui-test/init.test.ts @@ -1,4 +1,4 @@ -import { assert } from 'console'; +import * as assert from "assert"; import { VSBrowser, WebDriver } from 'vscode-extension-tester'; describe('Init test suite', () => { @@ -14,4 +14,4 @@ describe('Init test suite', () => { const title = await driver.getTitle(); assert(title != ""); }); -}); \ No newline at end of file +}) \ No newline at end of file diff --git a/src/test/ui-test/negative.test.ts b/src/test/ui-test/negative.test.ts new file mode 100644 index 0000000..802b1c3 --- /dev/null +++ b/src/test/ui-test/negative.test.ts @@ -0,0 +1,68 @@ +import { VSController } from './utils/vs-controller'; +import { EditorView } from 'vscode-extension-tester'; +import { CppCreatorExtHelper } from './utils/extension-helper'; +import { ClassHelper } from './utils/class-helper'; +import * as assert from "assert"; +import * as fs from "fs"; +import { ExtensionSettings } from './utils/extension-settings-helper'; + +describe('Negative-cases test suite', () => { + const workSpaceDir = "/tmp/cppWs"; + let vsController = new VSController(); + let cppCreatorExt = new CppCreatorExtHelper(); + let ext_settings = new ExtensionSettings(); + + before(async () => { + await vsController.openWorkspace(workSpaceDir); + }); + + after(async ()=>{ + await ext_settings.setSetPath(undefined); + await ext_settings.setCreateFolder(false); + }) + + beforeEach(async ()=>{ + }) + + it('Clicking escape when prompt shows up, with some input', async () => { + await cppCreatorExt.openPromptSendESC("test"); + assert(await VSController.isNotificationSent("Your class could NOT be created!")); + assert(!fs.existsSync(workSpaceDir+"/test.cpp")) + assert(!fs.existsSync(workSpaceDir+"/test.h")) + }) + + it('Empty class in main-prompt', async () => { + await cppCreatorExt.openExtPromptByContextMenu("", workSpaceDir); + + assert(await VSController.isNotificationSent("Your class could NOT be created!")); + assert(!fs.existsSync(workSpaceDir+"/.cpp")) + assert(!fs.existsSync(workSpaceDir+"/.h")) + }) + + it('Classname > 60 chars in main-prompt', async () => { + await cppCreatorExt.openExtPromptByCmdPallette("abcdefghijklmnopqrstuvwxyjzabcdefghijklmnopqrstuvwxyjzabcdefghijklmnopqrstuvwxyjz"); + + assert(await VSController.isNotificationSent("Class name to long!")); + assert(!fs.existsSync(workSpaceDir+"/abcdefghijklmnopqrstuvwxyjzabcdefghijklmnopqrstuvwxyjzabcdefghijklmnopqrstuvwxyjz.cpp")) + assert(!fs.existsSync(workSpaceDir+"/abcdefghijklmnopqrstuvwxyjzabcdefghijklmnopqrstuvwxyjzabcdefghijklmnopqrstuvwxyjz.h")) + }) + + it('Classname contains invalid characters in main-prompt', async () => { + // e.g. ' ' + await cppCreatorExt.openExtPromptByCmdPallette("a b c"); + + assert(await VSController.isNotificationSent("Class name should not have spaces!")); + assert(!fs.existsSync(workSpaceDir+"/a b c.cpp")) + assert(!fs.existsSync(workSpaceDir+"/a b c.h")) + }) + + it('Empty path in "setPath"', async () => { + await ext_settings.setSetPath(true); + await cppCreatorExt.openExtPromptWithPathPromptByCmdPallette("test", ""); + + // files just create without setPath + assert(await ClassHelper.fileExistsWithContent("test", workSpaceDir+"/test.h", ClassHelper.defaultHeaderContent("test"), true)); + assert(await ClassHelper.fileExistsWithContent("test", workSpaceDir+"/test.cpp", ClassHelper.defaultClassContent("test"), true)); + await ext_settings.setSetPath(false); + }) +}); \ No newline at end of file diff --git a/src/test/ui-test/replacement-commands.test.ts b/src/test/ui-test/replacement-commands.test.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/test/ui-test/utils/class-helper.ts b/src/test/ui-test/utils/class-helper.ts new file mode 100644 index 0000000..f6e4215 --- /dev/null +++ b/src/test/ui-test/utils/class-helper.ts @@ -0,0 +1,106 @@ +import * as fs from "fs"; +import { until } from "./util"; +import * as assert from "assert"; +import { VSController } from "./vs-controller"; + + + +export class ClassHelper +{ + static async fileExists(path: string) + { + if(await until(()=>fs.existsSync(path), 1000)) + { + console.error(`${path} does not exist.`) + return false; + } + assert(fs.existsSync(path)); + return true; + } + + static async fileExistsGetContent(path: string, className: string) + { + const pathWithoutFileName = path.substring(0, path.lastIndexOf("/")); + const expNotif = `Your class "${className}" has been created! (@${pathWithoutFileName})`; + assert(await VSController.isNotificationSent(expNotif)); + + assert(await this.fileExists(path)); + + let fileContent = ""; + + await until(()=>{ + fileContent = fs.readFileSync(path).toString(); + return fileContent != ""; + }, 2000); + + return fileContent; + } + + static async fileExistsWithContent(className: string, path: string, content: string, deleteAfterwards: boolean) + { + assert(content != ""); + + const pathWithoutFileName = path.substring(0, path.lastIndexOf("/")); + const expNotif = `Your class "${className}" has been created! (@${pathWithoutFileName})`; + assert(await VSController.isNotificationSent(expNotif)); + + assert(await this.fileExists(path)); + + let fileContent = ""; + + await until(()=>{ + fileContent = fs.readFileSync(path).toString(); + return fileContent != ""; + }, 2000); + + if(fileContent != content) + { + console.error(`contents are not equal.`); + console.error("in file:", fileContent); + console.error("exp:", content); + return false; + } + + if(deleteAfterwards) + { + fs.unlinkSync(path); + } + + return true; + } + + static defaultHeaderContent(className: string) + { + return `#ifndef ${className.toUpperCase()}_H +#define ${className.toUpperCase()}_H + +#pragma once + +class ${className} +{ +public: + ${className}(); + ~${className}(); + +private: + +}; + +#endif`; + } + + static defaultClassContent(className: string) + { + return `#include "${className}.h" + +${className}::${className}() +{ + +} + +${className}::~${className}() +{ + +}`; + } +} \ No newline at end of file diff --git a/src/test/ui-test/utils/copied-test-lib.ts b/src/test/ui-test/utils/copied-test-lib.ts new file mode 100644 index 0000000..cb32b95 --- /dev/null +++ b/src/test/ui-test/utils/copied-test-lib.ts @@ -0,0 +1,26 @@ +import { By } from "vscode-extension-tester"; + +export const locators = { + SettingsEditor: { + title: 'Settings', + itemRow: By.className('monaco-list-row'), + header: By.className('settings-header'), + tabs: By.className('settings-tabs-widget'), + actions: By.className('actions-container'), + action: (label: string) => By.xpath(`.//a[@title='${label}']`), + settingConstructor: (title: string, category: string) => By.xpath(`.//div[@class='monaco-tl-row' and .//span/text()='${title}' and .//span/text()='${category}: ']`), + settingDesctiption: By.className('setting-item-description'), + settingLabel: By.className('setting-item-label'), + settingCategory: By.className('setting-item-category'), + comboSetting: By.css('select'), + comboOption: By.className('option-text'), + comboValue: 'title', + textSetting: By.css('input'), + textAreaSetting: By.css('textarea'), + textAreaConent: By.css('div.mirror'), + checkboxSetting: By.className('setting-value-checkbox'), + checkboxChecked: 'aria-checked', + linkButton: By.className('edit-in-settings-button'), + itemCount: By.className('settings-count-widget') + } +} \ No newline at end of file diff --git a/src/test/ui-test/utils/extension-helper.ts b/src/test/ui-test/utils/extension-helper.ts new file mode 100644 index 0000000..a219d8f --- /dev/null +++ b/src/test/ui-test/utils/extension-helper.ts @@ -0,0 +1,159 @@ + +import { ActivityBar, InputBox, Key, TreeItem, VSBrowser, Workbench } from "vscode-extension-tester"; + +import * as path from "path"; +import * as fs from "fs"; +import * as assert from "assert"; +import { until } from "./util"; + +export class CppCreatorExtHelper +{ + async openExtPromptByShortcut(classNamePrompt: string) + { + // heavy workaround + await VSBrowser.instance.driver.actions().keyDown(Key.ALT).keyUp(Key.CONTROL).keyUp(Key.SHIFT).sendKeys("x").perform(); + + let inputBox = await new InputBox().wait(); + await inputBox.setText(classNamePrompt); + await inputBox.confirm(); + + // fix workaround + await VSBrowser.instance.driver.actions().keyDown(Key.CONTROL).keyDown(Key.SHIFT).keyUp(Key.ALT).perform(); + } + + async openExtPromptByContextMenu(classNamePrompt: string, wsPath: string) + { + const explorer = await new ActivityBar().getViewControl("Explorer"); + assert(explorer != undefined); + const explorerView = await explorer.openView(); + + const explorerContent = explorerView.getContent(); + + const wsExplorer = await explorerContent.getSection("Untitled (Workspace)"); + await wsExplorer.expand(); + + const wsName = path.basename(wsPath); + let clickableItem = await wsExplorer.findItem(wsName); + assert(clickableItem != undefined); + + const explorerMenu = await clickableItem.openContextMenu(); + const createElem = await explorerMenu.getItem("Create C++ Class"); + assert(createElem != undefined); + + await createElem.click(); + + let inputBox = await new InputBox().wait(); + await inputBox.setText(classNamePrompt); + await inputBox.confirm(); + } + + async openExtPromptByContextMenuWithChild(classNamePrompt: string, wsPath: string, child: string) + { + // create child-entry first + const childPath = wsPath+"/"+child; + if(!fs.existsSync(childPath)) + { + fs.mkdirSync(childPath); + + } + + + const explorer = await new ActivityBar().getViewControl("Explorer"); + assert(explorer != undefined); + const explorerView = await explorer.openView(); + const explorerContent = explorerView.getContent(); + const wsExplorer = await explorerContent.getSection("Untitled (Workspace)"); + + + await wsExplorer.expand(); + assert(fs.existsSync(childPath)) + await wsExplorer.click(); + const refreshAction = await wsExplorer.getAction("Refresh Explorer"); + assert(refreshAction != undefined); + await refreshAction.click(); + + const wsName = path.basename(wsPath); + let clickableItem = await wsExplorer.findItem(wsName) as TreeItem; + assert(clickableItem != undefined); + await clickableItem.expand() + + let clickableChildItem: TreeItem | undefined = undefined; + await until(async ()=>{ + try + { + const childItem = await clickableItem.findChildItem(path.basename(childPath)); + assert(childItem != undefined); + clickableChildItem = childItem; + return true; + } + catch(e) + { + return false; + } + + }, 2000); + + assert(clickableChildItem != undefined); + const explorerMenu = await (clickableChildItem as TreeItem).openContextMenu(); + const createElem = await explorerMenu.getItem("Create C++ Class"); + assert(createElem != undefined); + await createElem.click(); + + let inputBox = await new InputBox().wait(); + await inputBox.setText(classNamePrompt); + await inputBox.confirm(); + } + + async openExtPromptByCmdPallette(classNamePrompt: string) + { + await new Workbench().executeCommand("Create C++ Class"); + + let inputBox = await new InputBox().wait(); + await inputBox.setText(classNamePrompt); + await inputBox.confirm(); + } + + async openExtPromptWithPathPromptByCmdPallette(classNamePrompt: string, path: string) + { + await new Workbench().executeCommand("Create C++ Class"); + + { + let inputBox = await new InputBox().wait(); + await inputBox.setText(classNamePrompt); + await inputBox.confirm(); + } + + { + let inputBox = await new InputBox().wait(); + await inputBox.setText(path); + await inputBox.confirm(); + } + + } + + async openPromptSendESC(classNamePrompt: string) + { + await new Workbench().executeCommand("Create C++ Class"); + + let inputBox = await new InputBox().wait(); + await inputBox.setText(classNamePrompt); + await VSBrowser.instance.driver.actions().sendKeys(Key.ESCAPE).perform(); + } + + async openPromptSendESCToPath(classNamePrompt: string, pathPrompt: string) + { + await new Workbench().executeCommand("Create C++ Class"); + + { + let inputBox = await new InputBox().wait(); + await inputBox.setText(classNamePrompt); + await inputBox.submit(); + } + await VSBrowser.instance.driver.sleep(1000); + { + let inputBox = await new InputBox().wait(); + await inputBox.setText(pathPrompt); + await VSBrowser.instance.driver.actions().sendKeys(Key.ESCAPE).perform(); + } + } +} \ No newline at end of file diff --git a/src/test/ui-test/utils/extension-settings-helper.ts b/src/test/ui-test/utils/extension-settings-helper.ts new file mode 100644 index 0000000..af6ab96 --- /dev/null +++ b/src/test/ui-test/utils/extension-settings-helper.ts @@ -0,0 +1,137 @@ +import * as assert from "assert"; +import { EditorView, LinkSetting, Workbench, TextEditor, Setting } from "vscode-extension-tester"; +import { getMultiLineSettingById } from "./multiline-setting"; + +export class ExtensionSettings +{ + async getSettingById(id: string): Promise + { + const settingsEditor = await new Workbench().openSettings(); + const setting = await settingsEditor.findSettingByID(id); + assert(setting != undefined); + + return setting; + } + + async isCreateFolderEnabled() : Promise + { + const setting = await this.getSettingById("cpp.creator.createFolder"); + + return (await setting.getValue() as boolean); + } + + async setCreateFolder(val: boolean) + { + const setting = await this.getSettingById("cpp.creator.createFolder"); + + await setting.setValue(val); + } + + // HeaderFileContentPreset + async getHeaderFileContentPreset() : Promise + { + const setting = await getMultiLineSettingById("cpp.creator.headerFileContentPreset"); + + return (await setting.getValue() as string); + } + + async setHeaderFileContentPreset(val: string) + { + const setting = await getMultiLineSettingById("cpp.creator.headerFileContentPreset"); + + await setting.setValue(val); + } + + // SourceFileContentPreset + async getSourceFileContentPreset() : Promise + { + const setting = await getMultiLineSettingById("cpp.creator.sourceFileContentPreset"); + + return (await setting.getValue() as string); + } + + async setSourceFileContentPreset(val: string) + { + const setting = await getMultiLineSettingById("cpp.creator.sourceFileContentPreset"); + + await setting.setValue(val) + } + + // HeaderFileNamePreset + async getHeaderFileNamePreset() : Promise + { + const setting = await this.getSettingById("cpp.creator.headerFileNamePreset"); + + return await setting.getValue() as string; + } + + async setHeaderFileNamePreset(val: string) + { + const setting = await this.getSettingById("cpp.creator.headerFileNamePreset"); + + await setting.setValue(val) + } + + // SourceFileNamePreset + async getSourceFileNamePreset() : Promise + { + const setting = await this.getSettingById("cpp.creator.sourceFileNamePreset"); + + return await setting.getValue() as string; + } + + async setSourceFileNamePreset(val: string) + { + const setting = await this.getSettingById("cpp.creator.sourceFileNamePreset"); + + await setting.setValue(val) + } + + // SetPath + async isSetPath() : Promise + { + const setting = await this.getSettingById("cpp.creator.setPath") as LinkSetting; + await setting.openLink(); + + // get editor text + let settingsJsonEditor = await new EditorView().openEditor("settings.json") as TextEditor; + let settingsJsonText = await settingsJsonEditor.getText(); + + // parse json + let settingsJson = JSON.parse(settingsJsonText); + + // get json value + + if(settingsJson["cpp.creator.setPath"] == "") + { + settingsJson["cpp.creator.setPath"] = undefined; + await settingsJsonEditor.setText(JSON.stringify(settingsJson, null, 2)); + if(await settingsJsonEditor.isDirty()) + await settingsJsonEditor.save(); + + return undefined; + } + + return settingsJson["cpp.creator.setPath"] as boolean | string; + } + + async setSetPath(val: boolean | string | undefined) + { + const setting = await this.getSettingById("cpp.creator.setPath") as LinkSetting; + await setting.openLink(); + + // get editor text + let settingsJsonEditor = await new EditorView().openEditor("settings.json") as TextEditor; + let settingsJsonText = await settingsJsonEditor.getText(); + + // parse json + let settingsJson = JSON.parse(settingsJsonText); + + // set json value + settingsJson["cpp.creator.setPath"] = val; + + await settingsJsonEditor.setText(JSON.stringify(settingsJson, null, 2)); + if(await settingsJsonEditor.isDirty()) + await settingsJsonEditor.save(); + } +} \ No newline at end of file diff --git a/src/test/ui-test/utils/multiline-setting.ts b/src/test/ui-test/utils/multiline-setting.ts new file mode 100644 index 0000000..7b87e7f --- /dev/null +++ b/src/test/ui-test/utils/multiline-setting.ts @@ -0,0 +1,102 @@ +import { By, CheckboxSetting, ComboSetting, LinkSetting, Setting, SettingsEditor, TextSetting, WebElement, Workbench } from "vscode-extension-tester"; +import { locators } from "./copied-test-lib"; +import assert = require("assert"); +import { until } from "./util"; + +export async function createSetting(element: WebElement, title: string, category: string, settingsEditor: SettingsEditor): Promise { + await element.findElement(locators.SettingsEditor.settingConstructor(title, category)); + try { + // try a combo setting + await element.findElement(locators.SettingsEditor.comboSetting); + return new ComboSetting(locators.SettingsEditor.settingConstructor(title, category), settingsEditor); + } catch (err) { + try { + // try text setting + await element.findElement(locators.SettingsEditor.textSetting); + return new TextSetting(locators.SettingsEditor.settingConstructor(title, category), settingsEditor); + } catch (err) { + try { + // try checkbox setting + await element.findElement(locators.SettingsEditor.checkboxSetting); + return new CheckboxSetting(locators.SettingsEditor.settingConstructor(title, category), settingsEditor); + } catch (err) { + // try link setting + try { + await element.findElement(locators.SettingsEditor.linkButton); + return new LinkSetting(locators.SettingsEditor.settingConstructor(title, category), settingsEditor); + } catch (err) { + // try multiline setting + try + { + await element.findElement(locators.SettingsEditor.textAreaSetting); + return new TextAreaSetting(locators.SettingsEditor.settingConstructor(title, category), settingsEditor); + } + catch(err) + { + throw new Error('Setting type not supported'); + } + } + } + } + } +} + +export async function getMultiLineSettingById(id: string): Promise +{ + const settingsEditor = await new Workbench().openSettings(); + const invalidSetting = await settingsEditor.findSettingByID(id); + assert(invalidSetting == undefined); // Dont expect it to be found. + + const count = await settingsEditor.findElement(By.className('settings-count-widget')); + let textCount = await count.getText(); + await settingsEditor.getDriver().wait(async function() { + await new Promise(res => setTimeout(res, 1500)); + const text = await count.getText(); + if (text !== textCount) { + textCount = text; + return false; + } + return true; + }); + + let setting!: Setting; + const items = await settingsEditor.findElements(locators.SettingsEditor.itemRow); + for (const item of items) { + try { + const _category = (await (await item.findElement(locators.SettingsEditor.settingCategory)).getText()).replace(':', ''); + const _title = await (await item.findElement(locators.SettingsEditor.settingLabel)).getText(); + if(id !== '') { + const modifiedId = id.toLowerCase().replace(/\s/g, '').trim(); + const modifiedTitle = _title.toLowerCase().replace(/\s/g, '').trim(); + if(!modifiedId.endsWith(modifiedTitle)) { + continue; + } + } + return await (await createSetting(item, _title, _category, settingsEditor)).wait(); + } catch (err) + { + } + } + return setting; +} + +export class TextAreaSetting extends Setting { + + async getValue(): Promise { + const input = await this.findElement(locators.SettingsEditor.textAreaConent); + + let textContent = ""; + await until(async ()=> { + textContent = await input.getAttribute("textContent") + return textContent != ""; + }, 2000); + + return textContent; + } + + async setValue(value: string): Promise { + const input = await this.findElement(locators.SettingsEditor.textAreaSetting); + await input.clear(); + await input.sendKeys(value); + } +} \ No newline at end of file diff --git a/src/test/ui-test/utils/util.ts b/src/test/ui-test/utils/util.ts new file mode 100644 index 0000000..d45ca39 --- /dev/null +++ b/src/test/ui-test/utils/util.ts @@ -0,0 +1,34 @@ +import * as fs from "fs"; + +export async function until(conditionFunction: any, timeout: any) { + return new Promise((resolve, reject) => { + const startTime = Date.now(); + + const poll = async () => { + if (await conditionFunction()) { + resolve(""); + } else { + const elapsedTime = Date.now() - startTime; + if (elapsedTime >= timeout) { + reject(new Error("Timeout exceeded while waiting for condition to be met")); + } else { + setTimeout(poll, 200); + } + } + }; + + poll(); + }); +} + +export async function waitUntilFileWithEndingCreated(ending: string, dir: string) +{ + let files: string[] = []; + await until(()=>{ + const wsContents = fs.readdirSync(dir) + files = wsContents.filter((elem: string)=> elem.endsWith(ending)); + + return files.length > 0; + }, 2000); + return files; +} diff --git a/src/test/ui-test/utils/vs-controller.ts b/src/test/ui-test/utils/vs-controller.ts new file mode 100644 index 0000000..4069f23 --- /dev/null +++ b/src/test/ui-test/utils/vs-controller.ts @@ -0,0 +1,63 @@ +import { Workbench, TitleBar, InputBox, VSBrowser, Key, EditorView, Notification } from 'vscode-extension-tester'; +import * as fs from "fs"; +import * as assert from "assert"; +import { until } from './util'; + +export class VSController +{ + async openWorkspace(pathWs: string) + { + // check if workspace is already open + const titleBarTitle = (await new TitleBar().getTitle()); + if(titleBarTitle.includes("Untitled (Workspace)")) + { + console.warn(`ws ${pathWs} is already open.`); + return; + } + + if(!fs.existsSync(pathWs)) + { + fs.mkdirSync(pathWs) + } + + const titleBar = new TitleBar(); + const item = await titleBar.getItem('File'); + const fileMenu = await item!.select(); + const openItem = await fileMenu.getItem("Add Folder to Workspace..."); + await openItem!.select(); + const input = await InputBox.create(); + await input.setText(pathWs); + await input.confirm(); + } + + async openNewEmptyEditor() + { + await new Workbench().executeCommand("File: New Untitled Text File"); + //await VSBrowser.instance.driver.actions().sendKeys(Key.chord(Key.CONTROL, 'n')).perform(); + // Check if an editor with untitled document is open + const editorView = new EditorView(); + const titles = await editorView.getOpenEditorTitles(); + const untitledEditor = titles.find((title)=>title.startsWith("Untitled-")); + assert(untitledEditor != undefined); + await new EditorView().openEditor(untitledEditor as string); + } + + static async isNotificationSent(text: string) + { + const notifications = await new Workbench().getNotifications(); + + await until(async ()=>{ + for(let notif of notifications) + { + if(await notif.getMessage() == text) + { + return true; + } + } + + return false; + }, 2000); + + return true; + } +} \ No newline at end of file diff --git a/src/vscode_helper.ts b/src/vscode_helper.ts index bee934d..36dec42 100755 --- a/src/vscode_helper.ts +++ b/src/vscode_helper.ts @@ -26,7 +26,7 @@ export abstract class vscode_helper { if (!res) { - vscode.window.showErrorMessage("Your Class could not be created!"); + vscode.window.showErrorMessage("Your class could NOT be created!"); return false; } else if (res.length > 60)