Skip to content

Commit

Permalink
feat: for of support for typescript
Browse files Browse the repository at this point in the history
  • Loading branch information
marabesi committed Jun 30, 2024
1 parent 6fff16d commit 183830f
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 19 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ Smelly test is an extension that helps developers mitigate test smells in their

## Features

- Identify if statements in the test code
- Identify **if** statements in the test code
- Identify **for of** loops in the test code

## Available at

Expand Down
30 changes: 28 additions & 2 deletions vscode/src/modules/smells-finder/languages/TypescriptSmells.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,19 @@ export class TypescriptSmells implements SmellsFinder {
const ast = ts.createSourceFile('temp.ts', this.code, ts.ScriptTarget.ES2020, true);
const nodes = this.findIfStatements(ast);

return nodes.map(ifStmt => {
const forOfs = this.findForOfStatements(ast).map(forStmt => {
const { line: startLine, character } = ts.getLineAndCharacterOfPosition(ast, forStmt.getStart());
const { line: endLine, character: endCharacter } = ts.getLineAndCharacterOfPosition(ast, forStmt.getEnd());

return SmellsBuilder.forOfStatement(
startLine + 1,
endLine + 1,
character,
endCharacter,
);
});

const ifs = nodes.map(ifStmt => {
const { line: startLine, character } = ts.getLineAndCharacterOfPosition(ast, ifStmt.getStart());
const { line: endLine, character: endCharacter } = ts.getLineAndCharacterOfPosition(ast, ifStmt.getEnd());

Expand All @@ -23,9 +35,11 @@ export class TypescriptSmells implements SmellsFinder {
endCharacter,
);
});

return ifs.concat(forOfs);
}

findIfStatements(node: ts.Node, ifStatements: ts.IfStatement[] = []): ts.IfStatement[] {
private findIfStatements(node: ts.Node, ifStatements: ts.IfStatement[] = []): ts.IfStatement[] {
if (ts.isIfStatement(node)) {
ifStatements.push(node);
}
Expand All @@ -36,4 +50,16 @@ export class TypescriptSmells implements SmellsFinder {

return ifStatements;
}

private findForOfStatements(node: ts.Node, forOfStatements: ts.ForOfStatement[] = []): ts.ForOfStatement[] {
if (ts.isForOfStatement(node)) {
forOfStatements.push(node);
}

node.forEachChild(child => {
this.findForOfStatements(child, forOfStatements);
});

return forOfStatements;
}
}
41 changes: 32 additions & 9 deletions vscode/src/modules/smells-finder/test/smells-detector.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,22 @@ import * as assert from 'assert';
import { suite, test } from 'mocha';
import { SmellDetector } from '../smells-detector';

const IF_STATEMENT = 'if-statement';
const FOR_OF = 'for-of-statement';

const JAVASCRIPT = 'javascript';
const TYPESCRIPT = 'typescript';

suite('Smelly Extension Test Suite', () => {
suite('Javascript', () => {
test('find if in the test code', () => {
const code = `const a = 1;
if (a === 1) {}`;

const smellDetector = new SmellDetector(code, 'javascript');
const smellDetector = new SmellDetector(code, JAVASCRIPT);
const result = smellDetector.findAll();

assert.equal(result[0].type, 'if-statement');
assert.equal(result[0].type, IF_STATEMENT);
assert.equal(result[0].lineStart, 2);
assert.equal(result[0].lineEnd, 2);
assert.equal(result[0].startAt, 0);
Expand All @@ -25,10 +31,10 @@ for (const i of lists) {
}`;

const smellDetector = new SmellDetector(code, 'javascript');
const smellDetector = new SmellDetector(code, JAVASCRIPT);
const result = smellDetector.findAll();

assert.equal(result[0].type, 'for-of-statement');
assert.equal(result[0].type,FOR_OF);
assert.equal(result[0].lineStart, 3);
assert.equal(result[0].lineEnd, 5);
assert.equal(result[0].startAt, 0);
Expand All @@ -41,10 +47,10 @@ for (const i of lists) {
const code = `const a: number = 1;
if (a === 1) { }`;

const smellDetector = new SmellDetector(code, 'typescript');
const smellDetector = new SmellDetector(code, TYPESCRIPT);
const result = smellDetector.findAll();

assert.equal(result[0].type, 'if-statement');
assert.equal(result[0].type, IF_STATEMENT);
assert.equal(result[0].lineStart, 2, 'line start');
assert.equal(result[0].lineEnd, 2, 'line end');
assert.equal(result[0].startAt, 0, 'start at');
Expand All @@ -58,7 +64,7 @@ if (a === 2) {
console.log('this is a test');
}`;

const smellDetector = new SmellDetector(code, 'typescript');
const smellDetector = new SmellDetector(code, TYPESCRIPT);
const result = smellDetector.findAll();

assert.equal(result.length, 2);
Expand All @@ -71,14 +77,31 @@ if (a === 2) {
console.log('this is a test');
}`;

const smellDetector = new SmellDetector(code, 'typescript');
const smellDetector = new SmellDetector(code, TYPESCRIPT);
const result = smellDetector.findAll();

assert.equal(result[1].type, 'if-statement');
assert.equal(result[1].type, IF_STATEMENT);
assert.equal(result[1].lineStart, 3, 'line start');
assert.equal(result[1].lineEnd, 5, 'line end');
assert.equal(result[1].startAt, 0, 'start at');
assert.equal(result[1].endsAt, 1, 'end at');
});

test('find for in the test code', () => {
const code = `const lists: any[] = [{}, {}];
for (const i of lists) {
}`;

const smellDetector = new SmellDetector(code, TYPESCRIPT);
const result = smellDetector.findAll();

assert.equal(result[0].type,FOR_OF);
assert.equal(result[0].lineStart, 3);
assert.equal(result[0].lineEnd, 5);
assert.equal(result[0].startAt, 0);
assert.equal(result[0].endsAt, 1);
});
});
});
24 changes: 17 additions & 7 deletions vscode/src/modules/vscode/test/suite/extension.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,25 @@ import * as assert from 'assert';
import * as path from 'path';
import * as vscode from 'vscode';

const testFolderLocationForJavascript = '../../../../../../src/modules/vscode/dataset/javascript';
const testFolderLocationForTypescript = '../../../../../../src/modules/vscode/dataset/typescript';
function fileForJavascript(file: string) {
const testFolderLocationForJavascript = '../../../../../../src/modules/vscode/dataset/javascript';
return testFolderLocationForJavascript + '/' + file;
}

function fileFortypescript(file: string) {
const testFolderLocationForTypescript = '../../../../../../src/modules/vscode/dataset/typescript';
return testFolderLocationForTypescript + '/' + file;
}

suite('Smelly Extension Test Suite', () => {
[
{ language: 'javascript', file: testFolderLocationForJavascript + '/script_with_if.test.js', expectedTestSmell: 1 },
{ language: 'javascript', file: testFolderLocationForJavascript + '/real_test_with_if.test.js', expectedTestSmell: 7 },
{ language: 'javascript', file: testFolderLocationForJavascript + '/script_with_for.test.js', expectedTestSmell: 1 },
{ language: 'typescript', file: testFolderLocationForTypescript + '/script_with_if.test.ts', expectedTestSmell: 1 },
{ language: 'javascript', file: fileForJavascript('/script_with_if.test.js'), expectedTestSmell: 1 },
{ language: 'javascript', file: fileForJavascript('real_test_with_if.test.js'), expectedTestSmell: 7 },
{ language: 'javascript', file: fileForJavascript('script_with_for.test.js'), expectedTestSmell: 1 },
// typescript
{ language: 'typescript', file: fileFortypescript('script_with_if.test.ts'), expectedTestSmell: 1 },
{ language: 'typescript', file: fileFortypescript('script_with_for.test.ts'), expectedTestSmell: 1 },
// typescript
].forEach(({ language, file, expectedTestSmell }) => {
test(`Shows smelly in diagnostics panel, language: ${language}, file: ${file}, expected smells: ${expectedTestSmell}`, async () => {
const currentFile = path.join(__dirname + file);
Expand All @@ -31,7 +41,7 @@ suite('Smelly Extension Test Suite', () => {
});

test('ignores files that are not for test', async () => {
const file = testFolderLocationForJavascript + '/script_with_if.js';
const file = fileForJavascript('script_with_if.js');
const language = 'javascript';

const currentFile = path.join(__dirname + file);
Expand Down

0 comments on commit 183830f

Please sign in to comment.