From 92c6ec1eedaa1052129854b59b02868293cc4551 Mon Sep 17 00:00:00 2001 From: Victor Diez Date: Thu, 19 Dec 2024 16:16:02 +0100 Subject: [PATCH] wip --- packages/jsts/src/rules/S100/unit.test.ts | 204 ++-- packages/jsts/src/rules/S101/unit.test.ts | 108 +- packages/jsts/src/rules/S104/unit.test.ts | 54 +- packages/jsts/src/rules/S105/unit.test.ts | 94 +- packages/jsts/src/rules/S1066/unit.test.ts | 115 ++- packages/jsts/src/rules/S1067/unit.test.ts | 304 +++--- packages/jsts/src/rules/S1068/unit.test.ts | 188 ++-- packages/jsts/src/rules/S107/unit.test.ts | 223 ++-- packages/jsts/src/rules/S1110/unit.test.ts | 308 +++--- packages/jsts/src/rules/S1119/unit.test.ts | 44 +- packages/jsts/src/rules/S1121/unit.test.ts | 448 ++++---- packages/jsts/src/rules/S1125/unit.test.ts | 132 +-- packages/jsts/src/rules/S1126/unit.test.ts | 466 ++++----- packages/jsts/src/rules/S1128/unit.test.ts | 515 +++++----- packages/jsts/src/rules/S1134/unit.test.ts | 120 +-- packages/jsts/src/rules/S1135/unit.test.ts | 132 +-- packages/jsts/src/rules/S1154/unit.test.ts | 138 +-- packages/jsts/src/rules/S117/unit.test.ts | 276 ++--- packages/jsts/src/rules/S1192/unit.test.ts | 268 ++--- packages/jsts/src/rules/S1219/unit.test.ts | 88 +- packages/jsts/src/rules/S1226/unit.test.ts | 148 +-- packages/jsts/src/rules/S124/unit.test.ts | 204 ++-- packages/jsts/src/rules/S125/unit.test.ts | 342 ++++--- packages/jsts/src/rules/S126/unit.test.ts | 92 +- packages/jsts/src/rules/S1264/unit.test.ts | 66 +- packages/jsts/src/rules/S128/unit.test.ts | 164 +-- packages/jsts/src/rules/S1291/unit.test.ts | 112 +- packages/jsts/src/rules/S1301/unit.test.ts | 82 +- packages/jsts/src/rules/S131/unit.test.ts | 134 +-- packages/jsts/src/rules/S1313/unit.test.ts | 86 +- packages/jsts/src/rules/S134/unit.test.ts | 172 ++-- packages/jsts/src/rules/S135/unit.test.ts | 24 +- packages/jsts/src/rules/S138/unit.test.ts | 164 +-- packages/jsts/src/rules/S1439/unit.test.ts | 84 +- packages/jsts/src/rules/S1451/unit.test.ts | 124 +-- packages/jsts/src/rules/S1472/unit.test.ts | 238 ++--- packages/jsts/src/rules/S1479/unit.test.ts | 82 +- packages/jsts/src/rules/S1481/unit.test.ts | 246 ++--- packages/jsts/src/rules/S1488/unit.test.ts | 554 +++++----- packages/jsts/src/rules/S1515/unit.test.ts | 304 +++--- packages/jsts/src/rules/S1523/unit.test.ts | 176 ++-- packages/jsts/src/rules/S1526/unit.test.ts | 142 +-- packages/jsts/src/rules/S1527/unit.test.ts | 100 +- packages/jsts/src/rules/S1528/unit.test.ts | 156 +-- packages/jsts/src/rules/S1529/unit.test.ts | 252 ++--- packages/jsts/src/rules/S1530/unit.test.ts | 80 +- packages/jsts/src/rules/S1533/unit.test.ts | 424 ++++---- packages/jsts/src/rules/S1534/unit.test.ts | 142 +-- packages/jsts/src/rules/S1535/unit.test.ts | 88 +- packages/jsts/src/rules/S1541/unit.test.ts | 346 +++---- packages/jsts/src/rules/S1607/unit.test.ts | 22 +- packages/jsts/src/rules/S1751/unit.test.ts | 116 +-- packages/jsts/src/rules/S1763/unit.test.ts | 78 +- packages/jsts/src/rules/S1764/unit.test.ts | 442 ++++---- packages/jsts/src/rules/S1821/unit.test.ts | 172 ++-- packages/jsts/src/rules/S1848/unit.test.ts | 168 +-- packages/jsts/src/rules/S1854/unit.test.ts | 248 ++--- packages/jsts/src/rules/S1862/unit.test.ts | 506 ++++----- packages/jsts/src/rules/S1871/unit.test.ts | 520 +++++----- packages/jsts/src/rules/S1940/unit.test.ts | 198 ++-- packages/jsts/src/rules/S1994/unit.test.ts | 144 +-- packages/jsts/src/rules/S2004/unit.test.ts | 32 +- packages/jsts/src/rules/S2068/unit.test.ts | 134 +-- packages/jsts/src/rules/S2077/unit.test.ts | 226 ++-- packages/jsts/src/rules/S2092/unit.test.ts | 462 ++++----- packages/jsts/src/rules/S2123/unit.test.ts | 108 +- packages/jsts/src/rules/S2137/unit.test.ts | 304 +++--- packages/jsts/src/rules/S2138/unit.test.ts | 8 +- packages/jsts/src/rules/S2187/unit.test.ts | 106 +- packages/jsts/src/rules/S2189/unit.test.ts | 210 ++-- packages/jsts/src/rules/S2201/unit.test.ts | 250 ++--- packages/jsts/src/rules/S2208/unit.test.ts | 88 +- packages/jsts/src/rules/S2234/unit.test.ts | 226 ++-- packages/jsts/src/rules/S2245/unit.test.ts | 80 +- packages/jsts/src/rules/S2251/unit.test.ts | 352 +++---- packages/jsts/src/rules/S2255/unit.test.ts | 128 +-- packages/jsts/src/rules/S2259/unit.test.ts | 390 +++---- packages/jsts/src/rules/S2301/unit.test.ts | 200 ++-- packages/jsts/src/rules/S2310/unit.test.ts | 194 ++-- packages/jsts/src/rules/S2376/unit.test.ts | 70 +- packages/jsts/src/rules/S2392/unit.test.ts | 134 +-- packages/jsts/src/rules/S2424/unit.test.ts | 112 +- packages/jsts/src/rules/S2428/unit.test.ts | 276 ++--- packages/jsts/src/rules/S2430/unit.test.ts | 44 +- packages/jsts/src/rules/S2589/unit.test.ts | 560 +++++----- packages/jsts/src/rules/S2598/unit.test.ts | 288 +++--- packages/jsts/src/rules/S2612/unit.test.ts | 192 ++-- packages/jsts/src/rules/S2681/unit.test.ts | 208 ++-- packages/jsts/src/rules/S2692/unit.test.ts | 88 +- packages/jsts/src/rules/S2703/unit.test.ts | 144 +-- packages/jsts/src/rules/S2737/unit.test.ts | 122 +-- packages/jsts/src/rules/S2755/unit.test.ts | 120 +-- packages/jsts/src/rules/S2757/unit.test.ts | 200 ++-- packages/jsts/src/rules/S2814/unit.test.ts | 44 +- packages/jsts/src/rules/S2817/unit.test.ts | 104 +- packages/jsts/src/rules/S2819/unit.test.ts | 202 ++-- packages/jsts/src/rules/S2871/unit.test.ts | 951 ++++++++--------- packages/jsts/src/rules/S2990/unit.test.ts | 222 ++-- packages/jsts/src/rules/S2999/unit.test.ts | 224 ++-- packages/jsts/src/rules/S3001/unit.test.ts | 122 +-- packages/jsts/src/rules/S3003/unit.test.ts | 136 +-- packages/jsts/src/rules/S3317/unit.test.ts | 264 ++--- packages/jsts/src/rules/S3330/unit.test.ts | 462 ++++----- packages/jsts/src/rules/S3358/unit.test.ts | 120 +-- packages/jsts/src/rules/S3402/unit.test.ts | 218 ++-- packages/jsts/src/rules/S3403/unit.test.ts | 305 +++--- packages/jsts/src/rules/S3498/unit.test.ts | 64 +- packages/jsts/src/rules/S3499/unit.test.ts | 110 +- packages/jsts/src/rules/S3500/unit.test.ts | 50 +- packages/jsts/src/rules/S3512/unit.test.ts | 90 +- packages/jsts/src/rules/S3513/unit.test.ts | 90 +- packages/jsts/src/rules/S3514/unit.test.ts | 156 +-- packages/jsts/src/rules/S3516/unit.test.ts | 394 +++---- packages/jsts/src/rules/S3524/unit.test.ts | 204 ++-- packages/jsts/src/rules/S3525/unit.test.ts | 138 +-- packages/jsts/src/rules/S3531/unit.test.ts | 146 +-- packages/jsts/src/rules/S3533/unit.test.ts | 192 ++-- packages/jsts/src/rules/S3579/unit.test.ts | 106 +- packages/jsts/src/rules/S3616/unit.test.ts | 158 +-- packages/jsts/src/rules/S3626/unit.test.ts | 296 +++--- packages/jsts/src/rules/S3686/unit.test.ts | 102 +- packages/jsts/src/rules/S3696/unit.test.ts | 110 +- packages/jsts/src/rules/S3699/unit.test.ts | 158 +-- packages/jsts/src/rules/S3723/unit.test.ts | 32 +- packages/jsts/src/rules/S3735/unit.test.ts | 118 +-- packages/jsts/src/rules/S3757/unit.test.ts | 140 +-- packages/jsts/src/rules/S3758/unit.test.ts | 216 ++-- packages/jsts/src/rules/S3760/unit.test.ts | 306 +++--- packages/jsts/src/rules/S3776/unit.test.ts | 548 +++++----- packages/jsts/src/rules/S3782/unit.test.ts | 196 ++-- packages/jsts/src/rules/S3785/unit.test.ts | 110 +- packages/jsts/src/rules/S3796/unit.test.ts | 606 +++++------ packages/jsts/src/rules/S3798/unit.test.ts | 34 +- packages/jsts/src/rules/S3800/unit.test.ts | 648 ++++++------ packages/jsts/src/rules/S3801/unit.test.ts | 200 ++-- packages/jsts/src/rules/S3827/unit.test.ts | 172 ++-- packages/jsts/src/rules/S3854/unit.test.ts | 38 +- packages/jsts/src/rules/S3923/unit.test.ts | 296 +++--- packages/jsts/src/rules/S3972/unit.test.ts | 496 ++++----- packages/jsts/src/rules/S3973/unit.test.ts | 192 ++-- packages/jsts/src/rules/S3981/unit.test.ts | 494 ++++----- packages/jsts/src/rules/S3984/unit.test.ts | 126 +-- packages/jsts/src/rules/S4023/unit.test.ts | 56 +- packages/jsts/src/rules/S4030/unit.test.ts | 130 +-- packages/jsts/src/rules/S4043/unit.test.ts | 384 +++---- packages/jsts/src/rules/S4123/unit.test.ts | 232 ++--- packages/jsts/src/rules/S4138/unit.test.ts | 318 +++--- packages/jsts/src/rules/S4139/unit.test.ts | 150 +-- packages/jsts/src/rules/S4143/unit.test.ts | 328 +++--- packages/jsts/src/rules/S4144/unit.test.ts | 282 ++--- packages/jsts/src/rules/S4158/unit.test.ts | 426 ++++---- packages/jsts/src/rules/S4165/unit.test.ts | 222 ++-- packages/jsts/src/rules/S4275/unit.test.ts | 1080 ++++++++++---------- packages/jsts/src/rules/S4322/unit.test.ts | 456 +++++---- packages/jsts/src/rules/S4323/unit.test.ts | 174 ++-- packages/jsts/src/rules/S4324/unit.test.ts | 178 ++-- packages/jsts/src/rules/S4328/unit.test.ts | 462 ++++----- packages/jsts/src/rules/S4335/unit.test.ts | 150 +-- packages/jsts/src/rules/S4423/unit.test.ts | 244 ++--- packages/jsts/src/rules/S4426/unit.test.ts | 190 ++-- packages/jsts/src/rules/S4502/unit.test.ts | 162 +-- packages/jsts/src/rules/S4507/unit.test.ts | 114 ++- packages/jsts/src/rules/S4524/unit.test.ts | 66 +- packages/jsts/src/rules/S4619/unit.test.ts | 144 +-- packages/jsts/src/rules/S4621/unit.test.ts | 386 +++---- packages/jsts/src/rules/S4622/unit.test.ts | 240 ++--- packages/jsts/src/rules/S4623/unit.test.ts | 222 ++-- packages/jsts/src/rules/S4624/unit.test.ts | 258 ++--- packages/jsts/src/rules/S4634/unit.test.ts | 188 ++-- packages/jsts/src/rules/S4721/unit.test.ts | 142 +-- packages/jsts/src/rules/S4782/unit.test.ts | 506 ++++----- packages/jsts/src/rules/S4784/unit.test.ts | 162 +-- packages/jsts/src/rules/S4787/unit.test.ts | 192 ++-- packages/jsts/src/rules/S4798/unit.test.ts | 126 +-- packages/jsts/src/rules/S4817/unit.test.ts | 190 ++-- packages/jsts/src/rules/S4818/unit.test.ts | 68 +- packages/jsts/src/rules/S4822/unit.test.ts | 152 +-- packages/jsts/src/rules/S4823/unit.test.ts | 72 +- packages/jsts/src/rules/S4829/unit.test.ts | 72 +- packages/jsts/src/rules/S4830/unit.test.ts | 206 ++-- packages/jsts/src/rules/S5042/unit.test.ts | 302 +++--- packages/jsts/src/rules/S5332/unit.test.ts | 202 ++-- packages/jsts/src/rules/S5443/unit.test.ts | 68 +- packages/jsts/src/rules/S5527/unit.test.ts | 390 +++---- packages/jsts/src/rules/S5542/unit.test.ts | 330 +++--- packages/jsts/src/rules/S5547/unit.test.ts | 86 +- packages/jsts/src/rules/S5604/unit.test.ts | 312 +++--- packages/jsts/src/rules/S5659/unit.test.ts | 538 +++++----- packages/jsts/src/rules/S5689/unit.test.ts | 274 ++--- packages/jsts/src/rules/S5691/unit.test.ts | 72 +- packages/jsts/src/rules/S5693/unit.test.ts | 220 ++-- packages/jsts/src/rules/S5725/unit.test.ts | 120 +-- packages/jsts/src/rules/S5728/unit.test.ts | 194 ++-- packages/jsts/src/rules/S5730/unit.test.ts | 134 +-- packages/jsts/src/rules/S5732/unit.test.ts | 196 ++-- packages/jsts/src/rules/S5734/unit.test.ts | 266 ++--- packages/jsts/src/rules/S5736/unit.test.ts | 144 +-- packages/jsts/src/rules/S5739/unit.test.ts | 216 ++-- packages/jsts/src/rules/S5742/unit.test.ts | 254 ++--- packages/jsts/src/rules/S5743/unit.test.ts | 142 +-- packages/jsts/src/rules/S5757/unit.test.ts | 198 ++-- packages/jsts/src/rules/S5759/unit.test.ts | 98 +- packages/jsts/src/rules/S5842/unit.test.ts | 296 +++--- packages/jsts/src/rules/S5843/unit.test.ts | 1038 +++++++++---------- packages/jsts/src/rules/S5850/unit.test.ts | 164 +-- packages/jsts/src/rules/S5852/unit.test.ts | 172 ++-- packages/jsts/src/rules/S5856/unit.test.ts | 130 +-- packages/jsts/src/rules/S5860/unit.test.ts | 616 +++++------ packages/jsts/src/rules/S5863/unit.test.ts | 34 +- packages/jsts/src/rules/S5867/unit.test.ts | 204 ++-- packages/jsts/src/rules/S5868/unit.test.ts | 740 +++++++------- packages/jsts/src/rules/S5869/unit.test.ts | 438 ++++---- packages/jsts/src/rules/S5876/unit.test.ts | 92 +- packages/jsts/src/rules/S6019/unit.test.ts | 152 +-- packages/jsts/src/rules/S6035/unit.test.ts | 178 ++-- packages/jsts/src/rules/S6092/unit.test.ts | 40 +- packages/jsts/src/rules/S6268/unit.test.ts | 70 +- packages/jsts/src/rules/S6299/unit.test.ts | 165 +-- packages/jsts/src/rules/S6323/unit.test.ts | 266 ++--- packages/jsts/src/rules/S6324/unit.test.ts | 206 ++-- packages/jsts/src/rules/S6326/unit.test.ts | 116 +-- packages/jsts/src/rules/S6328/unit.test.ts | 330 +++--- packages/jsts/src/rules/S6331/unit.test.ts | 192 ++-- packages/jsts/src/rules/S6351/unit.test.ts | 352 +++---- packages/jsts/src/rules/S6353/unit.test.ts | 500 ++++----- packages/jsts/src/rules/S6418/unit.test.ts | 36 +- packages/jsts/src/rules/S6439/unit.test.ts | 234 ++--- packages/jsts/src/rules/S6479/unit.test.ts | 62 +- packages/jsts/src/rules/S6557/unit.test.ts | 78 +- packages/jsts/src/rules/S6582/unit.test.ts | 20 +- packages/jsts/src/rules/S6598/unit.test.ts | 41 +- packages/jsts/src/rules/S6606/unit.test.ts | 99 +- packages/jsts/src/rules/S6660/unit.test.ts | 74 +- packages/jsts/src/rules/S6661/unit.test.ts | 126 +-- packages/jsts/src/rules/S6666/unit.test.ts | 78 +- packages/jsts/src/rules/S6676/unit.test.ts | 246 ++--- packages/jsts/src/rules/S6679/unit.test.ts | 126 +-- packages/jsts/src/rules/S6749/unit.test.ts | 40 +- packages/jsts/src/rules/S6754/unit.test.ts | 40 +- packages/jsts/src/rules/S6788/unit.test.ts | 40 +- packages/jsts/src/rules/S6791/unit.test.ts | 54 +- packages/jsts/src/rules/S6957/unit.test.ts | 106 +- packages/jsts/src/rules/S6958/unit.test.ts | 470 ++++----- packages/jsts/src/rules/S6959/unit.test.ts | 50 +- packages/jsts/src/rules/S881/unit.test.ts | 238 ++--- packages/jsts/src/rules/S905/unit.test.ts | 152 +-- packages/jsts/src/rules/S930/unit.test.ts | 228 +++-- 247 files changed, 26347 insertions(+), 25797 deletions(-) diff --git a/packages/jsts/src/rules/S100/unit.test.ts b/packages/jsts/src/rules/S100/unit.test.ts index fea9be3640..e56bc065ea 100644 --- a/packages/jsts/src/rules/S100/unit.test.ts +++ b/packages/jsts/src/rules/S100/unit.test.ts @@ -16,7 +16,7 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTester = new RuleTester(); @@ -24,53 +24,54 @@ const DEFAULT_FORMAT = '^[_a-z][a-zA-Z0-9]*$'; const ALLOW_UPPERCASE = '^[A-Z][a-zA-Z0-9]*$'; describe('S100', () => { - ruleTester.run('Function names should comply with a naming convention', rule, { - valid: [ - { - code: ` + it('S100', () => { + ruleTester.run('Function names should comply with a naming convention', rule, { + valid: [ + { + code: ` function doSomething(){} function _doSomething(){} function* doSomething(){} let doSomething = function Object () {} `, - options: [{ format: DEFAULT_FORMAT }], - }, - { - code: ` + options: [{ format: DEFAULT_FORMAT }], + }, + { + code: ` class C { doSomething(){ } * doSomething (){} } `, - options: [{ format: DEFAULT_FORMAT }], - }, - { - code: ` + options: [{ format: DEFAULT_FORMAT }], + }, + { + code: ` function DoSomething() {} `, - options: [{ format: ALLOW_UPPERCASE }], - }, - { - code: ` + options: [{ format: ALLOW_UPPERCASE }], + }, + { + code: ` function Welcome() { const greeting = 'Hello, world!'; return

{greeting}

}`, - options: [{ format: DEFAULT_FORMAT }], - }, - { - code: ` + options: [{ format: DEFAULT_FORMAT }], + }, + { + code: ` const Welcome = () => { const greeting = 'Hello, world!'; return

{greeting}

}`, - options: [{ format: DEFAULT_FORMAT }], - }, - { - code: ` + options: [{ format: DEFAULT_FORMAT }], + }, + { + code: ` const Welcome = function() { const greeting = 'Hello, world!'; @@ -80,91 +81,91 @@ describe('S100', () => { ) }`, - options: [{ format: DEFAULT_FORMAT }], - }, - ], - invalid: [ - { - code: ` + options: [{ format: DEFAULT_FORMAT }], + }, + ], + invalid: [ + { + code: ` function DoSomething(){} `, - options: [{ format: DEFAULT_FORMAT }], - errors: [ - { - message: `Rename this 'DoSomething' function to match the regular expression '${DEFAULT_FORMAT}'.`, - line: 2, - endLine: 2, - column: 18, - endColumn: 29, - }, - ], - }, - { - code: ` + options: [{ format: DEFAULT_FORMAT }], + errors: [ + { + message: `Rename this 'DoSomething' function to match the regular expression '${DEFAULT_FORMAT}'.`, + line: 2, + endLine: 2, + column: 18, + endColumn: 29, + }, + ], + }, + { + code: ` function do_something(){} function* DoSomething(){} `, - options: [{ format: DEFAULT_FORMAT }], - errors: [ - { - messageId: `renameFunction`, - line: 2, - }, - { - messageId: `renameFunction`, - line: 3, - }, - ], - }, - { - code: ` + options: [{ format: DEFAULT_FORMAT }], + errors: [ + { + messageId: `renameFunction`, + line: 2, + }, + { + messageId: `renameFunction`, + line: 3, + }, + ], + }, + { + code: ` class C { DoSomething(){} * DoSomething (){} } `, - options: [{ format: DEFAULT_FORMAT }], - errors: [ - { - messageId: `renameFunction`, - line: 3, - }, - { - messageId: `renameFunction`, - line: 4, - }, - ], - }, - { - code: ` + options: [{ format: DEFAULT_FORMAT }], + errors: [ + { + messageId: `renameFunction`, + line: 3, + }, + { + messageId: `renameFunction`, + line: 4, + }, + ], + }, + { + code: ` var MyObj1 = function Object () { this.a = 1; }; `, - options: [{ format: DEFAULT_FORMAT }], - errors: [ - { - messageId: `renameFunction`, - line: 2, - }, - ], - }, - { - code: ` + options: [{ format: DEFAULT_FORMAT }], + errors: [ + { + messageId: `renameFunction`, + line: 2, + }, + ], + }, + { + code: ` var MyObj1 = () => { this.a = 1; }; `, - options: [{ format: DEFAULT_FORMAT }], - errors: [ - { - messageId: `renameFunction`, - line: 2, - }, - ], - }, - { - code: ` + options: [{ format: DEFAULT_FORMAT }], + errors: [ + { + messageId: `renameFunction`, + line: 2, + }, + ], + }, + { + code: ` var myObj = { Method1() {}, Method2: function() {}, @@ -180,14 +181,15 @@ describe('S100', () => { } }; `, - options: [{ format: DEFAULT_FORMAT }], - errors: [3, 4, 5, 6, 9, 12].map(line => { - return { - messageId: `renameFunction`, - line, - }; - }), - }, - ], + options: [{ format: DEFAULT_FORMAT }], + errors: [3, 4, 5, 6, 9, 12].map(line => { + return { + messageId: `renameFunction`, + line, + }; + }), + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S101/unit.test.ts b/packages/jsts/src/rules/S101/unit.test.ts index 045b2b925e..142234ef05 100644 --- a/packages/jsts/src/rules/S101/unit.test.ts +++ b/packages/jsts/src/rules/S101/unit.test.ts @@ -16,7 +16,7 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTester = new RuleTester(); @@ -24,64 +24,68 @@ const DEFAULT_FORMAT = '^[A-Z][a-zA-Z0-9]*$'; const CUSTOM_FORMAT = '^[_A-Z][a-zA-Z0-9]*$'; describe('S101', () => { - ruleTester.run('Class and interface names should comply with a naming convention', rule, { - valid: [ - { - code: ` + it('S101', () => { + ruleTester.run('Class and interface names should comply with a naming convention', rule, { + valid: [ + { + code: ` class MyClass {} var x = class y {} // Compliant, rule doesn't check class expressions interface MyInterface {} `, - options: [{ format: DEFAULT_FORMAT }], - }, - { - code: ` + options: [{ format: DEFAULT_FORMAT }], + }, + { + code: ` class MyClass {} class _MyClass {} interface _MyInterface {} `, - options: [{ format: CUSTOM_FORMAT }], - }, - ], - invalid: [ - { - code: `class my_class {}`, - options: [{ format: DEFAULT_FORMAT }], - errors: [ - { - message: `Rename class "my_class" to match the regular expression ${DEFAULT_FORMAT}.`, - line: 1, - endLine: 1, - column: 7, - endColumn: 15, - }, - ], - }, - { - code: `interface my_interface {}`, - options: [{ format: DEFAULT_FORMAT }], - errors: [ - { - message: `Rename interface "my_interface" to match the regular expression ${DEFAULT_FORMAT}.`, - }, - ], - }, - { - code: `class __MyClass {}`, - options: [{ format: CUSTOM_FORMAT }], - errors: [ - { message: `Rename class "__MyClass" to match the regular expression ${CUSTOM_FORMAT}.` }, - ], - }, - { - code: `interface __MyInterface {}`, - options: [{ format: CUSTOM_FORMAT }], - errors: [ - { - message: `Rename interface "__MyInterface" to match the regular expression ${CUSTOM_FORMAT}.`, - }, - ], - }, - ], + options: [{ format: CUSTOM_FORMAT }], + }, + ], + invalid: [ + { + code: `class my_class {}`, + options: [{ format: DEFAULT_FORMAT }], + errors: [ + { + message: `Rename class "my_class" to match the regular expression ${DEFAULT_FORMAT}.`, + line: 1, + endLine: 1, + column: 7, + endColumn: 15, + }, + ], + }, + { + code: `interface my_interface {}`, + options: [{ format: DEFAULT_FORMAT }], + errors: [ + { + message: `Rename interface "my_interface" to match the regular expression ${DEFAULT_FORMAT}.`, + }, + ], + }, + { + code: `class __MyClass {}`, + options: [{ format: CUSTOM_FORMAT }], + errors: [ + { + message: `Rename class "__MyClass" to match the regular expression ${CUSTOM_FORMAT}.`, + }, + ], + }, + { + code: `interface __MyInterface {}`, + options: [{ format: CUSTOM_FORMAT }], + errors: [ + { + message: `Rename interface "__MyInterface" to match the regular expression ${CUSTOM_FORMAT}.`, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S104/unit.test.ts b/packages/jsts/src/rules/S104/unit.test.ts index e1eafd9bc4..ca61b39767 100644 --- a/packages/jsts/src/rules/S104/unit.test.ts +++ b/packages/jsts/src/rules/S104/unit.test.ts @@ -16,44 +16,46 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S104', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Too many lines in file', rule, { - valid: [ - { - code: `a; + it('S104', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Too many lines in file', rule, { + valid: [ + { + code: `a; b; c;`, - options: [{ maximum: 3 }], - }, - { - code: `a; + options: [{ maximum: 3 }], + }, + { + code: `a; b; // comment c;`, - options: [{ maximum: 3 }], - }, - ], - invalid: [ - { - code: `a; + options: [{ maximum: 3 }], + }, + ], + invalid: [ + { + code: `a; b; c; // comment d;`, - options: [{ maximum: 3 }], - errors: [ - { - message: `This file has 4 lines, which is greater than 3 authorized. Split it into smaller files.`, - line: 0, - column: 1, - }, - ], - }, - ], + options: [{ maximum: 3 }], + errors: [ + { + message: `This file has 4 lines, which is greater than 3 authorized. Split it into smaller files.`, + line: 0, + column: 1, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S105/unit.test.ts b/packages/jsts/src/rules/S105/unit.test.ts index cf0d77f4c8..7a07eeae2d 100644 --- a/packages/jsts/src/rules/S105/unit.test.ts +++ b/packages/jsts/src/rules/S105/unit.test.ts @@ -16,55 +16,57 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTester = new RuleTester(); describe('S105', () => { - ruleTester.run('Tabulation characters should not be used', rule, { - valid: [ - { - code: ` foo`, - }, - { - code: ` foo`, - }, - ], - invalid: [ - { - code: `\t`, - errors: [ - { - message: 'Replace all tab characters in this file by sequences of white-spaces.', - line: 1, - column: 1, - }, - ], - }, - { - code: `foo(\tx);\n\t`, - errors: [ - { - message: 'Replace all tab characters in this file by sequences of white-spaces.', - line: 1, - column: 1, - }, - ], - }, - { - code: `foo(x)\n\t`, - errors: [ - { - message: 'Replace all tab characters in this file by sequences of white-spaces.', - line: 2, - column: 1, - }, - ], - }, - { - code: `foo(\tx);`, - errors: 1, - }, - ], + it('S105', () => { + ruleTester.run('Tabulation characters should not be used', rule, { + valid: [ + { + code: ` foo`, + }, + { + code: ` foo`, + }, + ], + invalid: [ + { + code: `\t`, + errors: [ + { + message: 'Replace all tab characters in this file by sequences of white-spaces.', + line: 1, + column: 1, + }, + ], + }, + { + code: `foo(\tx);\n\t`, + errors: [ + { + message: 'Replace all tab characters in this file by sequences of white-spaces.', + line: 1, + column: 1, + }, + ], + }, + { + code: `foo(x)\n\t`, + errors: [ + { + message: 'Replace all tab characters in this file by sequences of white-spaces.', + line: 2, + column: 1, + }, + ], + }, + { + code: `foo(\tx);`, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1066/unit.test.ts b/packages/jsts/src/rules/S1066/unit.test.ts index 717116122c..e85bcb8032 100644 --- a/packages/jsts/src/rules/S1066/unit.test.ts +++ b/packages/jsts/src/rules/S1066/unit.test.ts @@ -16,96 +16,101 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTester = new RuleTester(); describe('S1066', () => { - ruleTester.run('no-collapsible-if', rule, { - valid: [ - { - code: ` + it('S1066', () => { + ruleTester.run('no-collapsible-if', rule, { + valid: [ + { + code: ` if (x) { console.log(x); }`, - }, - { - code: ` + }, + { + code: ` if (x) { if (y) {} console.log(x); }`, - }, - { - code: ` + }, + { + code: ` if (x) { console.log(x); if (y) {} }`, - }, - { - code: ` + }, + { + code: ` if (x) { if (y) {} } else {}`, - }, - { - code: ` + }, + { + code: ` if (x) { if (y) {} else {} }`, - }, - ], + }, + ], - invalid: [ - { - code: ` + invalid: [ + { + code: ` if (x) { //^^ > {{Merge this if statement with the nested one.}} if (y) {} //^^ {{Nested "if" statement.}} }`, - options: ['sonar-runtime'], - errors: [ - { - messageId: 'sonarRuntime', - data: { - sonarRuntimeData: JSON.stringify({ - message: 'Merge this if statement with the nested one.', - secondaryLocations: [ - { - message: 'Nested "if" statement.', - column: 8, - line: 4, - endColumn: 10, - endLine: 4, - }, - ], - }), + options: ['sonar-runtime'], + errors: [ + { + messageId: 'sonarRuntime', + data: { + sonarRuntimeData: JSON.stringify({ + message: 'Merge this if statement with the nested one.', + secondaryLocations: [ + { + message: 'Nested "if" statement.', + column: 8, + line: 4, + endColumn: 10, + endLine: 4, + }, + ], + }), + }, + line: 2, + column: 7, + endLine: 2, + endColumn: 9, }, - line: 2, - column: 7, - endLine: 2, - endColumn: 9, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` if (x) if(y) {}`, - errors: [{ messageId: 'mergeNestedIfStatement' }], - }, - { - code: ` + errors: [{ messageId: 'mergeNestedIfStatement' }], + }, + { + code: ` if (x) { if(y) { if(z) { } } }`, - errors: [{ messageId: 'mergeNestedIfStatement' }, { messageId: 'mergeNestedIfStatement' }], - }, - ], + errors: [ + { messageId: 'mergeNestedIfStatement' }, + { messageId: 'mergeNestedIfStatement' }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1067/unit.test.ts b/packages/jsts/src/rules/S1067/unit.test.ts index 3055dea0b1..9ac2287d1b 100644 --- a/packages/jsts/src/rules/S1067/unit.test.ts +++ b/packages/jsts/src/rules/S1067/unit.test.ts @@ -17,7 +17,7 @@ import { rule } from './index.js'; import { EncodedMessage, IssueLocation } from '../helpers/index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTester = new RuleTester(); @@ -28,85 +28,86 @@ const options = [ ]; describe('S1067', () => { - ruleTester.run('Expressions should not be too complex', rule, { - valid: [ - { - code: `let b = 1 || 2 || 3 || 4`, - options, - }, - { - code: `let b = 1 && 2 && 4 && 4`, - options, - }, - { - code: `let b = 1 ? ( 2 ? ( 3 ? true : false ) : false ) : false;`, - options, - }, - { - code: `let b = foo(1 || 2 || 3, 1 || 2 || 3);`, - options, - }, - { - code: `let b = 1 || 2 || 3 || foo(1 || 2);`, - options, - }, - { - code: `let b = {x: 1 || 2 || 3, y: 1 || 2 || 3};`, - options, - }, - { - code: `let b = 1 || 2 || 3 || {x: 1 || 2};`, - options, - }, - { - code: `let b = function () {1 || 2 || 3 || 4};`, - options, - }, - { - code: `let b = 1 || 2 || 3 || function () {1 || 2};`, - options, - }, - { - code: `let b = 1 || 2 || 3 || function () {1 || 2 || function () {1 || 2}};`, - options, - }, - { - code: `let b = 1 || 2 || 3 || function f() {1 || 2 || function g() {1 || 2}};`, - options, - }, - { - code: `let b =
{1 || 2 || 3 || 4}
;`, - options, - }, - { - code: `let b = 1 || 2 || 3 ||
{1 || 2}
;`, - options, - }, - { - code: `let b = 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9 || 10;`, - options: [ - { - max: 10, - }, - ], - }, - ], - invalid: [ - invalid(` + it('S1067', () => { + ruleTester.run('Expressions should not be too complex', rule, { + valid: [ + { + code: `let b = 1 || 2 || 3 || 4`, + options, + }, + { + code: `let b = 1 && 2 && 4 && 4`, + options, + }, + { + code: `let b = 1 ? ( 2 ? ( 3 ? true : false ) : false ) : false;`, + options, + }, + { + code: `let b = foo(1 || 2 || 3, 1 || 2 || 3);`, + options, + }, + { + code: `let b = 1 || 2 || 3 || foo(1 || 2);`, + options, + }, + { + code: `let b = {x: 1 || 2 || 3, y: 1 || 2 || 3};`, + options, + }, + { + code: `let b = 1 || 2 || 3 || {x: 1 || 2};`, + options, + }, + { + code: `let b = function () {1 || 2 || 3 || 4};`, + options, + }, + { + code: `let b = 1 || 2 || 3 || function () {1 || 2};`, + options, + }, + { + code: `let b = 1 || 2 || 3 || function () {1 || 2 || function () {1 || 2}};`, + options, + }, + { + code: `let b = 1 || 2 || 3 || function f() {1 || 2 || function g() {1 || 2}};`, + options, + }, + { + code: `let b =
{1 || 2 || 3 || 4}
;`, + options, + }, + { + code: `let b = 1 || 2 || 3 ||
{1 || 2}
;`, + options, + }, + { + code: `let b = 1 || 2 || 3 || 4 || 5 || 6 || 7 || 8 || 9 || 10;`, + options: [ + { + max: 10, + }, + ], + }, + ], + invalid: [ + invalid(` let b = 1 || 2 || 3 || 4 || 5; //--^^---^^---^^---^^-- `), - invalid(` + invalid(` let b = 1 && 2 && 3 && 4 && 5; //--^^---^^---^^---^^-- `), - invalid(` + invalid(` function f() { let b = 1 || 2 || 3 || 4 || 5; //--^^---^^---^^---^^-- } `), - invalid(` + invalid(` function f() { let b = 1 || 2 || 3 || function g() { @@ -115,7 +116,7 @@ describe('S1067', () => { } } `), - invalid(` + invalid(` function f() { let b = 1 || 2 || 3 || function g() { @@ -127,99 +128,100 @@ describe('S1067', () => { } } `), - invalid( - ` + invalid( + ` let b = 1 ? true : false; //--^------------- `, - 0, - ), - ], + 0, + ), + ], + }); }); -}); -function invalid(code: string, max = 3) { - const issue = { - complexity: 0, - primaryLocation: {} as IssueLocation, - secondaryLocations: [] as IssueLocation[], - }; - const lines = code.split('\n'); - for (const [index, line] of lines.entries()) { - let found: RegExpMatchArray | null; + function invalid(code: string, max = 3) { + const issue = { + complexity: 0, + primaryLocation: {} as IssueLocation, + secondaryLocations: [] as IssueLocation[], + }; + const lines = code.split('\n'); + for (const [index, line] of lines.entries()) { + let found: RegExpMatchArray | null; - const regex = /\/\/\s*([-\^]+)/; - found = line.match(regex); - if (found) { - let marker = found[1]; - const column = line.indexOf(marker); - issue.primaryLocation = location(index, column, index, column + marker.length); + const regex = /\/\/\s*([-\^]+)/; + found = line.match(regex); + if (found) { + let marker = found[1]; + const column = line.indexOf(marker); + issue.primaryLocation = location(index, column, index, column + marker.length); - marker += ' '; - let secondaryStart = -1; - for (let i = 0; i < marker.length; ++i) { - if (marker[i] === '^') { - if (secondaryStart === -1) { - secondaryStart = i; - } - } else { - if (secondaryStart !== -1) { - issue.complexity += 1; - issue.secondaryLocations.push( - location(index, column + secondaryStart, index, column + i, '+1'), - ); - secondaryStart = -1; + marker += ' '; + let secondaryStart = -1; + for (let i = 0; i < marker.length; ++i) { + if (marker[i] === '^') { + if (secondaryStart === -1) { + secondaryStart = i; + } + } else { + if (secondaryStart !== -1) { + issue.complexity += 1; + issue.secondaryLocations.push( + location(index, column + secondaryStart, index, column + i, '+1'), + ); + secondaryStart = -1; + } } } } } + issue.secondaryLocations.sort((a, b) => b.column - a.column); + return { + code, + errors: [error(issue, max)], + options: [ + { + max, + }, + 'sonar-runtime', + ], + }; } - issue.secondaryLocations.sort((a, b) => b.column - a.column); - return { - code, - errors: [error(issue, max)], - options: [ - { - max, - }, - 'sonar-runtime', - ], - }; -} -function error( - issue: { - complexity: number; - primaryLocation: IssueLocation; - secondaryLocations: IssueLocation[]; - }, - max: number, -) { - const { line, column, endColumn, endLine } = issue.primaryLocation; - return { - message: encode(issue.complexity, max, issue.secondaryLocations), - line, - column: column + 1, - endColumn: endColumn + 1, - endLine, - }; -} + function error( + issue: { + complexity: number; + primaryLocation: IssueLocation; + secondaryLocations: IssueLocation[]; + }, + max: number, + ) { + const { line, column, endColumn, endLine } = issue.primaryLocation; + return { + message: encode(issue.complexity, max, issue.secondaryLocations), + line, + column: column + 1, + endColumn: endColumn + 1, + endLine, + }; + } -function encode(complexity: number, max: number, secondaryLocations: IssueLocation[]): string { - const encodedMessage: EncodedMessage = { - message: `Reduce the number of conditional operators (${complexity}) used in the expression (maximum allowed ${max}).`, - secondaryLocations, - cost: complexity - max, - }; - return JSON.stringify(encodedMessage); -} + function encode(complexity: number, max: number, secondaryLocations: IssueLocation[]): string { + const encodedMessage: EncodedMessage = { + message: `Reduce the number of conditional operators (${complexity}) used in the expression (maximum allowed ${max}).`, + secondaryLocations, + cost: complexity - max, + }; + return JSON.stringify(encodedMessage); + } -function location( - line: number, - column: number, - endLine: number, - endColumn: number, - message?: string, -): IssueLocation { - return { message, column, line, endColumn, endLine }; -} + function location( + line: number, + column: number, + endLine: number, + endColumn: number, + message?: string, + ): IssueLocation { + return { message, column, line, endColumn, endLine }; + } +}); diff --git a/packages/jsts/src/rules/S1068/unit.test.ts b/packages/jsts/src/rules/S1068/unit.test.ts index 4aed0d755b..c579a3a224 100644 --- a/packages/jsts/src/rules/S1068/unit.test.ts +++ b/packages/jsts/src/rules/S1068/unit.test.ts @@ -16,106 +16,108 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTester = new RuleTester(); describe('S1068', () => { - ruleTester.run(`Unused private class members should be removed`, rule, { - valid: [ - { - code: ` + it('S1068', () => { + ruleTester.run(`Unused private class members should be removed`, rule, { + valid: [ + { + code: ` class MyClass{ #foo = 123; bar(){return this.#foo;} }`, - }, - ], - invalid: [ - { - code: `class MyClass{ #foo = 123; }`, - errors: [ - { - messageId: 'unusedPrivateClassMember', - suggestions: [ - { - desc: 'Remove unused private class member', - output: `class MyClass{ }`, - }, - ], - }, - ], - }, - { - code: `class MyClass{ #foo(){} }`, - errors: [ - { - messageId: 'unusedPrivateClassMember', - suggestions: [ - { - desc: 'Remove unused private class member', - output: `class MyClass{ }`, - }, - ], - }, - ], - }, - { - code: `class MyClass{ get #foo(){} }`, - errors: [ - { - messageId: 'unusedPrivateClassMember', - suggestions: [ - { - desc: 'Remove unused private class member', - output: `class MyClass{ }`, - }, - ], - }, - ], - }, - { - code: `class MyClass{ set #foo(v){} }`, - errors: [ - { - messageId: 'unusedPrivateClassMember', - suggestions: [ - { - desc: 'Remove unused private class member', - output: `class MyClass{ }`, - }, - ], - }, - ], - }, - { - code: `class MyClass{ static #foo = 123; }`, - errors: [ - { - messageId: 'unusedPrivateClassMember', - suggestions: [ - { - desc: 'Remove unused private class member', - output: `class MyClass{ }`, - }, - ], - }, - ], - }, - { - code: `class MyClass{ static #foo(){} }`, - errors: [ - { - messageId: 'unusedPrivateClassMember', - suggestions: [ - { - desc: 'Remove unused private class member', - output: `class MyClass{ }`, - }, - ], - }, - ], - }, - ], + }, + ], + invalid: [ + { + code: `class MyClass{ #foo = 123; }`, + errors: [ + { + messageId: 'unusedPrivateClassMember', + suggestions: [ + { + desc: 'Remove unused private class member', + output: `class MyClass{ }`, + }, + ], + }, + ], + }, + { + code: `class MyClass{ #foo(){} }`, + errors: [ + { + messageId: 'unusedPrivateClassMember', + suggestions: [ + { + desc: 'Remove unused private class member', + output: `class MyClass{ }`, + }, + ], + }, + ], + }, + { + code: `class MyClass{ get #foo(){} }`, + errors: [ + { + messageId: 'unusedPrivateClassMember', + suggestions: [ + { + desc: 'Remove unused private class member', + output: `class MyClass{ }`, + }, + ], + }, + ], + }, + { + code: `class MyClass{ set #foo(v){} }`, + errors: [ + { + messageId: 'unusedPrivateClassMember', + suggestions: [ + { + desc: 'Remove unused private class member', + output: `class MyClass{ }`, + }, + ], + }, + ], + }, + { + code: `class MyClass{ static #foo = 123; }`, + errors: [ + { + messageId: 'unusedPrivateClassMember', + suggestions: [ + { + desc: 'Remove unused private class member', + output: `class MyClass{ }`, + }, + ], + }, + ], + }, + { + code: `class MyClass{ static #foo(){} }`, + errors: [ + { + messageId: 'unusedPrivateClassMember', + suggestions: [ + { + desc: 'Remove unused private class member', + output: `class MyClass{ }`, + }, + ], + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S107/unit.test.ts b/packages/jsts/src/rules/S107/unit.test.ts index ff442c0aa1..f5c477e8a4 100644 --- a/packages/jsts/src/rules/S107/unit.test.ts +++ b/packages/jsts/src/rules/S107/unit.test.ts @@ -16,7 +16,7 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const MAX_PARAMS_3 = 3; const MAX_PARAMS_5 = 5; @@ -26,117 +26,119 @@ const createOptions = (max: number) => { }; describe('S107', () => { - const ruleTester = new RuleTester(); - ruleTester.run(``, rule, { - valid: [ - { - code: `function f(a, b) {}`, - options: createOptions(MAX_PARAMS_5), - }, - { - code: `function f(a, b, c, d, e) {}`, - options: createOptions(MAX_PARAMS_5), - }, - { - code: `function f(a: any, b: any): any;`, - options: createOptions(MAX_PARAMS_5), - }, - { - code: `function f(a: any, b: any, c: any, d: any, e: any): any;`, - options: createOptions(MAX_PARAMS_5), - }, - { - code: `class C { m(a: any, b: any): any; }`, - options: createOptions(MAX_PARAMS_5), - }, - { - code: `class C { constructor(private a: any, public b: any) {} }`, - options: createOptions(MAX_PARAMS_5), - }, - { - code: ` + it('S107', () => { + const ruleTester = new RuleTester(); + ruleTester.run(``, rule, { + valid: [ + { + code: `function f(a, b) {}`, + options: createOptions(MAX_PARAMS_5), + }, + { + code: `function f(a, b, c, d, e) {}`, + options: createOptions(MAX_PARAMS_5), + }, + { + code: `function f(a: any, b: any): any;`, + options: createOptions(MAX_PARAMS_5), + }, + { + code: `function f(a: any, b: any, c: any, d: any, e: any): any;`, + options: createOptions(MAX_PARAMS_5), + }, + { + code: `class C { m(a: any, b: any): any; }`, + options: createOptions(MAX_PARAMS_5), + }, + { + code: `class C { constructor(private a: any, public b: any) {} }`, + options: createOptions(MAX_PARAMS_5), + }, + { + code: ` import { Component } from '@angular/core'; @Component({/* ... */}) class AppComponent { constructor(a, b, c, d, e, f) {} } `, - options: createOptions(MAX_PARAMS_3), - }, - { - code: `class C { constructor(private a: any, b: any, c: any, d: any) {} }`, - options: createOptions(MAX_PARAMS_3), - }, - ], - invalid: [ - { - code: `function f(a, b, c, d, e) {}`, - options: createOptions(MAX_PARAMS_3), - errors: [ - { - message: "Function 'f' has too many parameters (5). Maximum allowed is 3.", - line: 1, - column: 1, - endLine: 1, - endColumn: 11, - }, - ], - }, - { - code: `function f(a: any, b: any, c: any, d: any, e: any): any;`, - options: createOptions(MAX_PARAMS_3), - errors: [ - { - message: "Function declaration 'f' has too many parameters (5). Maximum allowed is 3.", - line: 1, - column: 1, - endLine: 1, - endColumn: 11, - }, - ], - }, - { - code: `class C { m(a: any, b: any, c: any, d: any, e: any): any; }`, - options: createOptions(MAX_PARAMS_3), - errors: [ - { - message: "Empty function 'm' has too many parameters (5). Maximum allowed is 3.", - line: 1, - column: 11, - endLine: 1, - endColumn: 12, - }, - ], - }, - { - code: `class C { constructor(a: any, b: any, c: any, d: any, e: any); }`, - options: createOptions(MAX_PARAMS_3), - errors: [ - { - message: - "Empty function 'constructor' has too many parameters (5). Maximum allowed is 3.", - line: 1, - column: 11, - endLine: 1, - endColumn: 22, - }, - ], - }, - { - code: `class C { constructor(private a: any, b: any, c: any, d: any, e: any) {} }`, - options: createOptions(MAX_PARAMS_3), - errors: [ - { - message: 'Constructor has too many parameters (5). Maximum allowed is 3.', - line: 1, - column: 11, - endLine: 1, - endColumn: 22, - }, - ], - }, - { - code: ` + options: createOptions(MAX_PARAMS_3), + }, + { + code: `class C { constructor(private a: any, b: any, c: any, d: any) {} }`, + options: createOptions(MAX_PARAMS_3), + }, + ], + invalid: [ + { + code: `function f(a, b, c, d, e) {}`, + options: createOptions(MAX_PARAMS_3), + errors: [ + { + message: "Function 'f' has too many parameters (5). Maximum allowed is 3.", + line: 1, + column: 1, + endLine: 1, + endColumn: 11, + }, + ], + }, + { + code: `function f(a: any, b: any, c: any, d: any, e: any): any;`, + options: createOptions(MAX_PARAMS_3), + errors: [ + { + message: + "Function declaration 'f' has too many parameters (5). Maximum allowed is 3.", + line: 1, + column: 1, + endLine: 1, + endColumn: 11, + }, + ], + }, + { + code: `class C { m(a: any, b: any, c: any, d: any, e: any): any; }`, + options: createOptions(MAX_PARAMS_3), + errors: [ + { + message: "Empty function 'm' has too many parameters (5). Maximum allowed is 3.", + line: 1, + column: 11, + endLine: 1, + endColumn: 12, + }, + ], + }, + { + code: `class C { constructor(a: any, b: any, c: any, d: any, e: any); }`, + options: createOptions(MAX_PARAMS_3), + errors: [ + { + message: + "Empty function 'constructor' has too many parameters (5). Maximum allowed is 3.", + line: 1, + column: 11, + endLine: 1, + endColumn: 22, + }, + ], + }, + { + code: `class C { constructor(private a: any, b: any, c: any, d: any, e: any) {} }`, + options: createOptions(MAX_PARAMS_3), + errors: [ + { + message: 'Constructor has too many parameters (5). Maximum allowed is 3.', + line: 1, + column: 11, + endLine: 1, + endColumn: 22, + }, + ], + }, + { + code: ` import { NotComponent } from '@angular/core'; import { Component } from 'not-angular-core'; @@ -159,9 +161,10 @@ describe('S107', () => { constructor(a, b, c, d, e, f) {} } `, - options: createOptions(MAX_PARAMS_3), - errors: 4, - }, - ], + options: createOptions(MAX_PARAMS_3), + errors: 4, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1110/unit.test.ts b/packages/jsts/src/rules/S1110/unit.test.ts index fb3b6e1e10..4bc71d5d98 100644 --- a/packages/jsts/src/rules/S1110/unit.test.ts +++ b/packages/jsts/src/rules/S1110/unit.test.ts @@ -16,182 +16,184 @@ */ import { rule } from './index.js'; import { NoTypeCheckingRuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTester = new NoTypeCheckingRuleTester({ parserOptions: { ecmaFeatures: { jsx: false } }, }); describe('S1110', () => { - ruleTester.run('Redundant pairs of parentheses should be removed', rule, { - valid: [ - { - code: `var a = typeof (38);`, - }, - { - code: `let a = typeof 39;`, - }, - { - code: `const a = (((a * b) + c) / 2.0);`, - }, - { - code: `if ((a = 3)) {}`, - }, - { - code: `while ((a = 3)) {}`, - }, - { - code: `do {} while ((a = 3))`, - }, - { - code: `let a = doSomething( /** @type MyObject */ (b));`, - }, - { - code: `let a = new MyClass((b = c));`, - }, - { - code: `[1, 2, 1, 1].reduce( ( acc, n ) => ( ( acc[n] += 1, acc ) ), [0, 0, 0] ) `, - }, - { - code: `with ((a = 3)) {}`, - }, - { - code: `switch ((a = 3)) { + it('S1110', () => { + ruleTester.run('Redundant pairs of parentheses should be removed', rule, { + valid: [ + { + code: `var a = typeof (38);`, + }, + { + code: `let a = typeof 39;`, + }, + { + code: `const a = (((a * b) + c) / 2.0);`, + }, + { + code: `if ((a = 3)) {}`, + }, + { + code: `while ((a = 3)) {}`, + }, + { + code: `do {} while ((a = 3))`, + }, + { + code: `let a = doSomething( /** @type MyObject */ (b));`, + }, + { + code: `let a = new MyClass((b = c));`, + }, + { + code: `[1, 2, 1, 1].reduce( ( acc, n ) => ( ( acc[n] += 1, acc ) ), [0, 0, 0] ) `, + }, + { + code: `with ((a = 3)) {}`, + }, + { + code: `switch ((a = 3)) { case 1: break; }`, - }, - { - code: `const a = import((a = 'fs'))`, - }, - ], - invalid: [ - { - code: `var a = typeof ((37));`, - errors: [ - { - message: `{"message":"Remove these redundant parentheses.","secondaryLocations":[{"column":20,"line":1,"endColumn":21,"endLine":1}]}`, - line: 1, - endLine: 1, - column: 16, - endColumn: 17, - suggestions: [ - { desc: 'Remove these redundant parentheses', output: 'var a = typeof (37);' }, - ], - }, - ], - options: ['sonar-runtime'], - }, - { - code: `const a = ((((a * b) + c)) / 2.0);`, - errors: [ - { - message: - '{"message":"Remove these redundant parentheses.","secondaryLocations":[{"column":25,"line":1,"endColumn":26,"endLine":1}]}', - line: 1, - endLine: 1, - column: 12, - endColumn: 13, - suggestions: [ - { - desc: 'Remove these redundant parentheses', - output: 'const a = (((a * b) + c) / 2.0);', - }, - ], - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + }, + { + code: `const a = import((a = 'fs'))`, + }, + ], + invalid: [ + { + code: `var a = typeof ((37));`, + errors: [ + { + message: `{"message":"Remove these redundant parentheses.","secondaryLocations":[{"column":20,"line":1,"endColumn":21,"endLine":1}]}`, + line: 1, + endLine: 1, + column: 16, + endColumn: 17, + suggestions: [ + { desc: 'Remove these redundant parentheses', output: 'var a = typeof (37);' }, + ], + }, + ], + options: ['sonar-runtime'], + }, + { + code: `const a = ((((a * b) + c)) / 2.0);`, + errors: [ + { + message: + '{"message":"Remove these redundant parentheses.","secondaryLocations":[{"column":25,"line":1,"endColumn":26,"endLine":1}]}', + line: 1, + endLine: 1, + column: 12, + endColumn: 13, + suggestions: [ + { + desc: 'Remove these redundant parentheses', + output: 'const a = (((a * b) + c) / 2.0);', + }, + ], + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` ( ( (a) ) )`, - errors: [ - { - message: - '{"message":"Remove these redundant parentheses.","secondaryLocations":[{"column":14,"line":6,"endColumn":15,"endLine":6}]}', - line: 2, - endLine: 2, - column: 9, - endColumn: 10, - suggestions: [ - { - desc: 'Remove these redundant parentheses', - output: ` + errors: [ + { + message: + '{"message":"Remove these redundant parentheses.","secondaryLocations":[{"column":14,"line":6,"endColumn":15,"endLine":6}]}', + line: 2, + endLine: 2, + column: 9, + endColumn: 10, + suggestions: [ + { + desc: 'Remove these redundant parentheses', + output: ` ( (a) ) `, - }, - ], - }, - { - message: - '{"message":"Remove these redundant parentheses.","secondaryLocations":[{"column":13,"line":5,"endColumn":14,"endLine":5}]}', - line: 3, - endLine: 3, - column: 10, - endColumn: 11, - suggestions: [ - { - desc: 'Remove these redundant parentheses', - output: ` + }, + ], + }, + { + message: + '{"message":"Remove these redundant parentheses.","secondaryLocations":[{"column":13,"line":5,"endColumn":14,"endLine":5}]}', + line: 3, + endLine: 3, + column: 10, + endColumn: 11, + suggestions: [ + { + desc: 'Remove these redundant parentheses', + output: ` ( (a) )`, - }, - ], - }, - ], - options: ['sonar-runtime'], - }, - { - code: `if (myBool) { ((obj)).methodCall() }`, - filename: 'file.ts', - errors: [ - { - message: - '{"message":"Remove these redundant parentheses.","secondaryLocations":[{"column":28,"line":1,"endColumn":29,"endLine":1}]}', - line: 1, - endLine: 1, - column: 15, - endColumn: 16, - suggestions: [ - { - desc: 'Remove these redundant parentheses', - output: 'if (myBool) { (obj).methodCall() }', - }, - ], - }, - ], - options: ['sonar-runtime'], - }, - { - code: `(((((a)))))`, - errors: 4, - }, - { - code: `let a = doSomething(( /** @type MyObject */ (b)));`, - errors: 1, - }, - { - code: `if (((a = 3))) {}`, - errors: 1, - }, - { - code: `while (((a = 3))) { ((a = 5)); }`, - errors: 2, - }, - { - code: `let a = new MyClass(((b = c)));`, - errors: 1, - }, - ], + }, + ], + }, + ], + options: ['sonar-runtime'], + }, + { + code: `if (myBool) { ((obj)).methodCall() }`, + filename: 'file.ts', + errors: [ + { + message: + '{"message":"Remove these redundant parentheses.","secondaryLocations":[{"column":28,"line":1,"endColumn":29,"endLine":1}]}', + line: 1, + endLine: 1, + column: 15, + endColumn: 16, + suggestions: [ + { + desc: 'Remove these redundant parentheses', + output: 'if (myBool) { (obj).methodCall() }', + }, + ], + }, + ], + options: ['sonar-runtime'], + }, + { + code: `(((((a)))))`, + errors: 4, + }, + { + code: `let a = doSomething(( /** @type MyObject */ (b)));`, + errors: 1, + }, + { + code: `if (((a = 3))) {}`, + errors: 1, + }, + { + code: `while (((a = 3))) { ((a = 5)); }`, + errors: 2, + }, + { + code: `let a = new MyClass(((b = c)));`, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1119/unit.test.ts b/packages/jsts/src/rules/S1119/unit.test.ts index a3c71a54a9..1933f38cc5 100644 --- a/packages/jsts/src/rules/S1119/unit.test.ts +++ b/packages/jsts/src/rules/S1119/unit.test.ts @@ -16,23 +16,24 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTester = new RuleTester(); describe('S1119', () => { - ruleTester.run('Labels should not be used', rule, { - valid: [ - { - code: ` + it('S1119', () => { + ruleTester.run('Labels should not be used', rule, { + valid: [ + { + code: ` let x = doSomething(); if (x <= 0) { doSomethingElse(); }`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` myLabel: { let x = doSomething(); if (x > 0) { @@ -41,16 +42,17 @@ describe('S1119', () => { doSomethingElse(); } `, - errors: [ - { - message: `Refactor the code to remove this label and the need for it.`, - line: 2, - endLine: 2, - column: 7, - endColumn: 14, - }, - ], - }, - ], + errors: [ + { + message: `Refactor the code to remove this label and the need for it.`, + line: 2, + endLine: 2, + column: 7, + endColumn: 14, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1121/unit.test.ts b/packages/jsts/src/rules/S1121/unit.test.ts index 37f05777a7..c75bd7745e 100644 --- a/packages/jsts/src/rules/S1121/unit.test.ts +++ b/packages/jsts/src/rules/S1121/unit.test.ts @@ -16,236 +16,238 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTester = new RuleTester(); describe('S1121', () => { - ruleTester.run('Assignments should not be made from within sub-expressions', rule, { - valid: [ - { - code: `let a = 0;`, - }, - { - code: `let a = 0, b = 1, c = 2;`, - }, - { - code: `let [a, b] = arr;`, - }, - { - code: `let {a, b} = obj;`, - }, - { - code: `a = 0;`, - }, - { - code: `function fun() { a = 0; }`, - }, - { - code: `a[i] = 0;`, - }, - { - code: `a.prop = 0;`, - }, - { - code: `(fun())[i] = 0;`, - }, - { - code: `a = b = c = 0;`, - }, - { - code: `a = 0, b = 0, c = 0;`, - }, - { - code: `({a, b} = obj);`, - }, - { - code: `([a, b] = arr);`, - }, - { - code: `for (var i = 0;;) {}`, - }, - { - code: `for (i = 0;;) {}`, - }, - { - code: `for (i = j = 0;;) {}`, - }, - { - code: `for (i, j = 0;;) {}`, - }, - { - code: `for (;; i = 0) {}`, - }, - { - code: `let f = a => b = a;`, - }, - { - code: `let f = a => (b = a);`, - }, - { - code: ` + it('S1121', () => { + ruleTester.run('Assignments should not be made from within sub-expressions', rule, { + valid: [ + { + code: `let a = 0;`, + }, + { + code: `let a = 0, b = 1, c = 2;`, + }, + { + code: `let [a, b] = arr;`, + }, + { + code: `let {a, b} = obj;`, + }, + { + code: `a = 0;`, + }, + { + code: `function fun() { a = 0; }`, + }, + { + code: `a[i] = 0;`, + }, + { + code: `a.prop = 0;`, + }, + { + code: `(fun())[i] = 0;`, + }, + { + code: `a = b = c = 0;`, + }, + { + code: `a = 0, b = 0, c = 0;`, + }, + { + code: `({a, b} = obj);`, + }, + { + code: `([a, b] = arr);`, + }, + { + code: `for (var i = 0;;) {}`, + }, + { + code: `for (i = 0;;) {}`, + }, + { + code: `for (i = j = 0;;) {}`, + }, + { + code: `for (i, j = 0;;) {}`, + }, + { + code: `for (;; i = 0) {}`, + }, + { + code: `let f = a => b = a;`, + }, + { + code: `let f = a => (b = a);`, + }, + { + code: ` while ((line = reader.readLine()) !== null) { doSomething(); } `, - }, - { - code: `while (a = 0) {}`, - }, - { - code: `do {} while (a = 0);`, - }, - { - code: `a || (a = 0);`, - }, - { - code: `a && (a = 0);`, - }, - { - code: `if (a, b = 0) {}`, - }, - { - code: `for (; i, j = 0;);`, - }, - { - code: `for (; (j = i) === 0;);`, - }, - { - code: `let a = b = c = 0;`, - }, - { - code: `let a = (b = (c = 0));`, - }, - { - code: `let f = a => (a = (b = 0));`, - }, - ], - invalid: [ - { - code: `if (a = 0) {}`, - errors: [ - { - message: `Extract the assignment of "a" from this expression.`, - line: 1, - endLine: 1, - column: 7, - endColumn: 8, - }, - ], - }, - { - code: `if (a = b = 0) {}`, - errors: 1, - }, - { - code: `if ((a = 0) && b) {}`, - errors: 1, - }, - { - code: `if ((fun())[i] = 0) {}`, - errors: 1, - }, - { - code: `(a = 0) ? b : c;`, - errors: 1, - }, - { - code: `a ? b = 0 : c;`, - errors: 1, - }, - { - code: `fun(a = 0);`, - errors: 1, - }, - { - code: `fun(a = b = c = 0);`, - errors: 1, - }, - { - code: `fun(a, b = 0);`, - errors: 1, - }, - { - code: `for (; i = 0;);`, - errors: 1, - }, - { - code: `for (; i = j = 0;);`, - errors: 1, - }, - { - code: `let a = [ a = 0 ];`, - errors: 1, - }, - { - code: `let a = { a: b = 0 };`, - errors: 1, - }, - { - code: `let a = { [a = 0]: b };`, - errors: 1, - }, - { - code: `function* foo() { yield (a = 0); }`, - errors: 1, - }, - { - code: `-(a = 0);`, - errors: 1, - }, - { - code: `(a = 0) % b;`, - errors: 1, - }, - { - code: `a[b = 0];`, - errors: 1, - }, - { - code: `(a = 0) ? b = 1 : c = 2`, - errors: 3, - }, - { - code: `new C(a = 0);`, - errors: 1, - }, - { - code: '`hello${a = 0}`', - errors: 1, - }, - { - code: 'myTag`hello${a = 0}`', - errors: 1, - }, - { - code: `class C { [a = 0]() {} }`, - errors: 1, - }, - { - code: `async () => await (a = 0);`, - errors: 1, - }, - { - code: `switch (a = 0) { case (b = 0): break; }`, - errors: 2, - }, - { - code: `function foo() { return (a = 0); }`, - errors: 1, - }, - { - code: `throw (a = 0);`, - errors: 1, - }, - { - code: `for (;a = 0;) {}`, - errors: 1, - }, - { - code: `(a = 0) || a;`, - errors: 1, - }, - ], + }, + { + code: `while (a = 0) {}`, + }, + { + code: `do {} while (a = 0);`, + }, + { + code: `a || (a = 0);`, + }, + { + code: `a && (a = 0);`, + }, + { + code: `if (a, b = 0) {}`, + }, + { + code: `for (; i, j = 0;);`, + }, + { + code: `for (; (j = i) === 0;);`, + }, + { + code: `let a = b = c = 0;`, + }, + { + code: `let a = (b = (c = 0));`, + }, + { + code: `let f = a => (a = (b = 0));`, + }, + ], + invalid: [ + { + code: `if (a = 0) {}`, + errors: [ + { + message: `Extract the assignment of "a" from this expression.`, + line: 1, + endLine: 1, + column: 7, + endColumn: 8, + }, + ], + }, + { + code: `if (a = b = 0) {}`, + errors: 1, + }, + { + code: `if ((a = 0) && b) {}`, + errors: 1, + }, + { + code: `if ((fun())[i] = 0) {}`, + errors: 1, + }, + { + code: `(a = 0) ? b : c;`, + errors: 1, + }, + { + code: `a ? b = 0 : c;`, + errors: 1, + }, + { + code: `fun(a = 0);`, + errors: 1, + }, + { + code: `fun(a = b = c = 0);`, + errors: 1, + }, + { + code: `fun(a, b = 0);`, + errors: 1, + }, + { + code: `for (; i = 0;);`, + errors: 1, + }, + { + code: `for (; i = j = 0;);`, + errors: 1, + }, + { + code: `let a = [ a = 0 ];`, + errors: 1, + }, + { + code: `let a = { a: b = 0 };`, + errors: 1, + }, + { + code: `let a = { [a = 0]: b };`, + errors: 1, + }, + { + code: `function* foo() { yield (a = 0); }`, + errors: 1, + }, + { + code: `-(a = 0);`, + errors: 1, + }, + { + code: `(a = 0) % b;`, + errors: 1, + }, + { + code: `a[b = 0];`, + errors: 1, + }, + { + code: `(a = 0) ? b = 1 : c = 2`, + errors: 3, + }, + { + code: `new C(a = 0);`, + errors: 1, + }, + { + code: '`hello${a = 0}`', + errors: 1, + }, + { + code: 'myTag`hello${a = 0}`', + errors: 1, + }, + { + code: `class C { [a = 0]() {} }`, + errors: 1, + }, + { + code: `async () => await (a = 0);`, + errors: 1, + }, + { + code: `switch (a = 0) { case (b = 0): break; }`, + errors: 2, + }, + { + code: `function foo() { return (a = 0); }`, + errors: 1, + }, + { + code: `throw (a = 0);`, + errors: 1, + }, + { + code: `for (;a = 0;) {}`, + errors: 1, + }, + { + code: `(a = 0) || a;`, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1125/unit.test.ts b/packages/jsts/src/rules/S1125/unit.test.ts index 575c89bade..1ed914e05b 100644 --- a/packages/jsts/src/rules/S1125/unit.test.ts +++ b/packages/jsts/src/rules/S1125/unit.test.ts @@ -16,78 +16,80 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1125', () => { - const ruleTester = new RuleTester(); + it('S1125', () => { + const ruleTester = new RuleTester(); - ruleTester.run('no-redundant-boolean', rule, { - valid: [ - { code: 'a === false;' }, - { code: 'a === true;' }, - { code: 'a !== false;' }, - { code: 'a !== true;' }, - { code: 'a == foo(true);' }, - { code: 'true < 0;' }, - { code: '~true;' }, - { code: '!foo;' }, - { code: 'if (foo(mayBeSomething || false)) {}' }, - { code: 'x ? y || false : z' }, - ], - invalid: [ - { - code: 'if (x == true) {}', - errors: [{ messageId: 'removeUnnecessaryBoolean', column: 10, endColumn: 14 }], - }, - { - code: 'if (x == false) {}', - errors: [{ messageId: 'removeUnnecessaryBoolean', column: 10, endColumn: 15 }], - }, - { - code: 'if (x || false) {}', - errors: [{ messageId: 'removeUnnecessaryBoolean', column: 10, endColumn: 15 }], - }, - { - code: 'if (x && false) {}', - errors: [{ messageId: 'removeUnnecessaryBoolean', column: 10, endColumn: 15 }], - }, + ruleTester.run('no-redundant-boolean', rule, { + valid: [ + { code: 'a === false;' }, + { code: 'a === true;' }, + { code: 'a !== false;' }, + { code: 'a !== true;' }, + { code: 'a == foo(true);' }, + { code: 'true < 0;' }, + { code: '~true;' }, + { code: '!foo;' }, + { code: 'if (foo(mayBeSomething || false)) {}' }, + { code: 'x ? y || false : z' }, + ], + invalid: [ + { + code: 'if (x == true) {}', + errors: [{ messageId: 'removeUnnecessaryBoolean', column: 10, endColumn: 14 }], + }, + { + code: 'if (x == false) {}', + errors: [{ messageId: 'removeUnnecessaryBoolean', column: 10, endColumn: 15 }], + }, + { + code: 'if (x || false) {}', + errors: [{ messageId: 'removeUnnecessaryBoolean', column: 10, endColumn: 15 }], + }, + { + code: 'if (x && false) {}', + errors: [{ messageId: 'removeUnnecessaryBoolean', column: 10, endColumn: 15 }], + }, - { - code: 'x || false ? 1 : 2', - errors: [{ messageId: 'removeUnnecessaryBoolean', column: 6, endColumn: 11 }], - }, + { + code: 'x || false ? 1 : 2', + errors: [{ messageId: 'removeUnnecessaryBoolean', column: 6, endColumn: 11 }], + }, - { - code: 'fn(!false)', - errors: [{ messageId: 'removeUnnecessaryBoolean', column: 5, endColumn: 10 }], - }, + { + code: 'fn(!false)', + errors: [{ messageId: 'removeUnnecessaryBoolean', column: 5, endColumn: 10 }], + }, - { - code: 'a == true == b;', - errors: [{ messageId: 'removeUnnecessaryBoolean', column: 6, endColumn: 10 }], - }, - { - code: 'a == b == false;', - errors: [{ messageId: 'removeUnnecessaryBoolean', column: 11, endColumn: 16 }], - }, - { - code: 'a == (true == b) == b;', - errors: [{ messageId: 'removeUnnecessaryBoolean', column: 7, endColumn: 11 }], - }, + { + code: 'a == true == b;', + errors: [{ messageId: 'removeUnnecessaryBoolean', column: 6, endColumn: 10 }], + }, + { + code: 'a == b == false;', + errors: [{ messageId: 'removeUnnecessaryBoolean', column: 11, endColumn: 16 }], + }, + { + code: 'a == (true == b) == b;', + errors: [{ messageId: 'removeUnnecessaryBoolean', column: 7, endColumn: 11 }], + }, - { - code: '!(true);', - errors: [{ messageId: 'removeUnnecessaryBoolean', column: 3, endColumn: 7 }], - }, - { - code: 'a == (false);', - errors: [{ messageId: 'removeUnnecessaryBoolean', column: 7, endColumn: 12 }], - }, + { + code: '!(true);', + errors: [{ messageId: 'removeUnnecessaryBoolean', column: 3, endColumn: 7 }], + }, + { + code: 'a == (false);', + errors: [{ messageId: 'removeUnnecessaryBoolean', column: 7, endColumn: 12 }], + }, - { - code: 'true && a;', - errors: [{ messageId: 'removeUnnecessaryBoolean', column: 1, endColumn: 5 }], - }, - ], + { + code: 'true && a;', + errors: [{ messageId: 'removeUnnecessaryBoolean', column: 1, endColumn: 5 }], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1126/unit.test.ts b/packages/jsts/src/rules/S1126/unit.test.ts index 7f0fe5f28c..f18c84598a 100644 --- a/packages/jsts/src/rules/S1126/unit.test.ts +++ b/packages/jsts/src/rules/S1126/unit.test.ts @@ -16,15 +16,16 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTester = new RuleTester(); describe('S1126', () => { - ruleTester.run('prefer-single-boolean-return', rule, { - valid: [ - { - code: ` + it('S1126', () => { + ruleTester.run('prefer-single-boolean-return', rule, { + valid: [ + { + code: ` function foo() { if (something) { return true; @@ -35,9 +36,9 @@ describe('S1126', () => { } } `, - }, - { - code: ` + }, + { + code: ` function foo() { if (something) { return x; @@ -46,9 +47,9 @@ describe('S1126', () => { } } `, - }, - { - code: ` + }, + { + code: ` function foo(y) { if (something) { return true; @@ -57,9 +58,9 @@ describe('S1126', () => { } } `, - }, - { - code: ` + }, + { + code: ` function foo() { if (something) { doSomething(); @@ -68,9 +69,9 @@ describe('S1126', () => { } } `, - }, - { - code: ` + }, + { + code: ` function foo() { if (something) { doSomething(); @@ -80,9 +81,9 @@ describe('S1126', () => { } } `, - }, - { - code: ` + }, + { + code: ` function foo() { if (something) { return; @@ -91,18 +92,18 @@ describe('S1126', () => { } } `, - }, - { - code: ` + }, + { + code: ` function foo() { if (something) { return true; } } `, - }, - { - code: ` + }, + { + code: ` function foo() { if (something) { return foo(true); @@ -111,9 +112,9 @@ describe('S1126', () => { } } `, - }, - { - code: ` + }, + { + code: ` function foo() { if (something) { var x; @@ -122,9 +123,9 @@ describe('S1126', () => { } } `, - }, - { - code: ` + }, + { + code: ` function foo() { if (something) { function f() {} @@ -134,11 +135,11 @@ describe('S1126', () => { } } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function foo() { if (something) { return true; @@ -162,16 +163,16 @@ describe('S1126', () => { } } `, - errors: [ - { - messageId: 'replaceIfThenElseByReturn', - line: 3, - column: 11, - endLine: 7, - endColumn: 12, - suggestions: [ - { - output: ` + errors: [ + { + messageId: 'replaceIfThenElseByReturn', + line: 3, + column: 11, + endLine: 7, + endColumn: 12, + suggestions: [ + { + output: ` function foo() { return !!(something); @@ -191,10 +192,10 @@ describe('S1126', () => { } } `, - desc: 'Replace with single return statement using "!!" cast', - }, - { - output: ` + desc: 'Replace with single return statement using "!!" cast', + }, + { + output: ` function foo() { return something; @@ -214,19 +215,19 @@ describe('S1126', () => { } } `, - desc: 'Replace with single return statement without cast (condition should be boolean!)', - }, - ], - }, - { - messageId: 'replaceIfThenElseByReturn', - line: 9, - column: 11, - endLine: 13, - endColumn: 12, - suggestions: [ - { - output: ` + desc: 'Replace with single return statement without cast (condition should be boolean!)', + }, + ], + }, + { + messageId: 'replaceIfThenElseByReturn', + line: 9, + column: 11, + endLine: 13, + endColumn: 12, + suggestions: [ + { + output: ` function foo() { if (something) { return true; @@ -246,19 +247,19 @@ describe('S1126', () => { } } `, - desc: 'Replace with single return statement', - }, - ], - }, - { - messageId: 'replaceIfThenElseByReturn', - line: 15, - column: 11, - endLine: 16, - endColumn: 29, - suggestions: [ - { - output: ` + desc: 'Replace with single return statement', + }, + ], + }, + { + messageId: 'replaceIfThenElseByReturn', + line: 15, + column: 11, + endLine: 16, + endColumn: 29, + suggestions: [ + { + output: ` function foo() { if (something) { return true; @@ -281,10 +282,10 @@ describe('S1126', () => { } } `, - desc: 'Replace with single return statement using "!!" cast', - }, - { - output: ` + desc: 'Replace with single return statement using "!!" cast', + }, + { + output: ` function foo() { if (something) { return true; @@ -307,19 +308,19 @@ describe('S1126', () => { } } `, - desc: 'Replace with single return statement without cast (condition should be boolean!)', - }, - ], - }, - { - messageId: 'replaceIfThenElseByReturn', - line: 18, - column: 11, - endLine: 22, - endColumn: 12, - suggestions: [ - { - output: ` + desc: 'Replace with single return statement without cast (condition should be boolean!)', + }, + ], + }, + { + messageId: 'replaceIfThenElseByReturn', + line: 18, + column: 11, + endLine: 22, + endColumn: 12, + suggestions: [ + { + output: ` function foo() { if (something) { return true; @@ -339,10 +340,10 @@ describe('S1126', () => { return !!(something); } `, - desc: 'Replace with single return statement using "!!" cast', - }, - { - output: ` + desc: 'Replace with single return statement using "!!" cast', + }, + { + output: ` function foo() { if (something) { return true; @@ -362,14 +363,14 @@ describe('S1126', () => { return something; } `, - desc: 'Replace with single return statement without cast (condition should be boolean!)', - }, - ], - }, - ], - }, - { - code: ` + desc: 'Replace with single return statement without cast (condition should be boolean!)', + }, + ], + }, + ], + }, + { + code: ` function fn() { if (foo) { if (something) { @@ -392,16 +393,16 @@ describe('S1126', () => { } } `, - errors: [ - { - messageId: 'replaceIfThenElseByReturn', - line: 4, - column: 13, - endLine: 6, - endColumn: 14, - suggestions: [ - { - output: ` + errors: [ + { + messageId: 'replaceIfThenElseByReturn', + line: 4, + column: 13, + endLine: 6, + endColumn: 14, + suggestions: [ + { + output: ` function fn() { if (foo) { return !!(something); @@ -421,10 +422,10 @@ describe('S1126', () => { } } `, - desc: 'Replace with single return statement using "!!" cast', - }, - { - output: ` + desc: 'Replace with single return statement using "!!" cast', + }, + { + output: ` function fn() { if (foo) { return something; @@ -444,19 +445,19 @@ describe('S1126', () => { } } `, - desc: 'Replace with single return statement without cast (condition should be boolean!)', - }, - ], - }, - { - messageId: 'replaceIfThenElseByReturn', - line: 11, - column: 13, - endLine: 13, - endColumn: 14, - suggestions: [ - { - output: ` + desc: 'Replace with single return statement without cast (condition should be boolean!)', + }, + ], + }, + { + messageId: 'replaceIfThenElseByReturn', + line: 11, + column: 13, + endLine: 13, + endColumn: 14, + suggestions: [ + { + output: ` function fn() { if (foo) { if (something) { @@ -476,14 +477,14 @@ describe('S1126', () => { } } `, - desc: 'Replace with single return statement', - }, - ], - }, - ], - }, - { - code: ` + desc: 'Replace with single return statement', + }, + ], + }, + ], + }, + { + code: ` function foo() { if (bar()) { if (baz()) { @@ -494,36 +495,36 @@ function foo() { } return qux(); }`, - errors: [ - { - messageId: 'replaceIfThenElseByReturn', - suggestions: [ - { - messageId: 'suggestCast', - output: ` + errors: [ + { + messageId: 'replaceIfThenElseByReturn', + suggestions: [ + { + messageId: 'suggestCast', + output: ` function foo() { if (bar()) { return !!(baz()); } return qux(); }`, - }, - { - messageId: 'suggestBoolean', - output: ` + }, + { + messageId: 'suggestBoolean', + output: ` function foo() { if (bar()) { return baz(); } return qux(); }`, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` function foo() { if (bar()) { if (baz()) { @@ -533,36 +534,36 @@ function foo() { } return qux(); }`, - errors: [ - { - messageId: 'replaceIfThenElseByReturn', - suggestions: [ - { - messageId: 'suggestCast', - output: ` + errors: [ + { + messageId: 'replaceIfThenElseByReturn', + suggestions: [ + { + messageId: 'suggestCast', + output: ` function foo() { if (bar()) { return !!(baz()); } return qux(); }`, - }, - { - messageId: 'suggestBoolean', - output: ` + }, + { + messageId: 'suggestBoolean', + output: ` function foo() { if (bar()) { return baz(); } return qux(); }`, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` function foo() { if (!bar()) { return true; @@ -570,23 +571,23 @@ function foo() { return false; } }`, - errors: [ - { - messageId: 'replaceIfThenElseByReturn', - suggestions: [ - { - messageId: 'suggest', - output: ` + errors: [ + { + messageId: 'replaceIfThenElseByReturn', + suggestions: [ + { + messageId: 'suggest', + output: ` function foo() { return !bar(); }`, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` function foo() { if (bar() > 0) { return true; @@ -594,23 +595,23 @@ function foo() { return false; } }`, - errors: [ - { - messageId: 'replaceIfThenElseByReturn', - suggestions: [ - { - messageId: 'suggest', - output: ` + errors: [ + { + messageId: 'replaceIfThenElseByReturn', + suggestions: [ + { + messageId: 'suggest', + output: ` function foo() { return bar() > 0; }`, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` function foo() { if (baz() > 0) { return false; @@ -618,23 +619,23 @@ function foo() { return true; } }`, - errors: [ - { - messageId: 'replaceIfThenElseByReturn', - suggestions: [ - { - messageId: 'suggest', - output: ` + errors: [ + { + messageId: 'replaceIfThenElseByReturn', + suggestions: [ + { + messageId: 'suggest', + output: ` function foo() { return !(baz() > 0); }`, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` function foo() { if (baz()) { return false; @@ -642,21 +643,22 @@ function foo() { return true; } }`, - errors: [ - { - messageId: 'replaceIfThenElseByReturn', - suggestions: [ - { - messageId: 'suggest', - output: ` + errors: [ + { + messageId: 'replaceIfThenElseByReturn', + suggestions: [ + { + messageId: 'suggest', + output: ` function foo() { return !(baz()); }`, - }, - ], - }, - ], - }, - ], + }, + ], + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1128/unit.test.ts b/packages/jsts/src/rules/S1128/unit.test.ts index e68c26f5fb..c81533d8e8 100644 --- a/packages/jsts/src/rules/S1128/unit.test.ts +++ b/packages/jsts/src/rules/S1128/unit.test.ts @@ -16,7 +16,8 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; + import parser from 'vue-eslint-parser'; import { dirname, join } from 'path'; import { fileURLToPath } from 'node:url'; @@ -33,144 +34,145 @@ const ruleTesterJsxFactory = new RuleTester({ }); describe('S1128', () => { - ruleTester.run('Unnecessary imports should be removed', rule, { - valid: [ - { - code: ` + it('S1128', () => { + ruleTester.run('Unnecessary imports should be removed', rule, { + valid: [ + { + code: ` import a from 'b'; console.log(a); `, - }, - { - code: ` + }, + { + code: ` import { a } from 'b'; console.log(a); `, - }, - { - code: ` + }, + { + code: ` import { a, b } from 'c'; console.log(a); console.log(b); `, - }, - { - code: ` + }, + { + code: ` import { a as b } from 'c'; console.log(b); `, - }, - { - code: `import React from 'react';`, - }, - { - code: ` + }, + { + code: `import React from 'react';`, + }, + { + code: ` import { a } from 'b'; `, - }, - { - code: ` + }, + { + code: ` import type { a } from 'b'; function f(param: a) {} `, - }, - { - code: ` + }, + { + code: ` /** @jsx jsx */ import { jsx } from '@emotion/core'`, - }, - { - code: ` + }, + { + code: ` /** @jsx jsx */ import { jsx } from 'any'`, - }, - { - code: ` + }, + { + code: ` import * as Foo from 'foobar'; let k: Foo; `, - }, - { - code: ` + }, + { + code: ` import * as Foo from 'foobar'; let k: Foo.Bar; `, - }, - { - code: ` + }, + { + code: ` import * as Foo from 'foobar'; let k: Foo.Bar.Baz; `, - }, - { - code: ` + }, + { + code: ` import * as Foo from 'foobar'; let k: Foo; `, - }, - { - code: ` + }, + { + code: ` import * as Foo from 'foobar'; let k: Bar; `, - }, - { - code: ` + }, + { + code: ` import * as Foo from 'foobar'; let k: Foo | Bar; `, - }, - { - code: ` + }, + { + code: ` import * as Foo from 'foobar'; let k: Foo & Bar; `, - }, - { - code: ` + }, + { + code: ` import * as Foo from 'foobar'; interface I extends Foo {} `, - }, - { - code: ` + }, + { + code: ` import * as Foo from 'foobar'; interface I extends Foo.Bar {} `, - }, - { - code: ` + }, + { + code: ` import * as Foo from 'foobar'; interface I extends Foo {} `, - }, - { - code: ` + }, + { + code: ` import * as Foo from 'foobar'; class C implements Foo {} `, - }, - { - code: ` + }, + { + code: ` import * as Foo from 'foobar'; class C implements Foo.Bar {} `, - }, - { - code: ` + }, + { + code: ` import * as Foo from 'foobar'; class C implements Foo {} `, - }, - { - code: ` + }, + { + code: ` import * as Foo from 'foobar'; class C extends Foo {} `, - }, - { - code: ` + }, + { + code: ` import type Alpha from 'alpha'; import type Beta from 'beta'; import type Gamma from 'gamma'; @@ -187,112 +189,112 @@ describe('S1128', () => { /** {@link Epsilon} */ `, - }, - ], - invalid: [ - { - code: `import a from 'b';`, - errors: [ - { - message: `Remove this unused import of 'a'.`, - line: 1, - endLine: 1, - column: 8, - endColumn: 9, - suggestions: [ - { - desc: `Remove this import statement`, - output: ``, - }, - ], - }, - ], - }, - { - code: `import a, {b} from 'b'; console.log(b)`, - errors: [ - { - messageId: 'removeUnusedImport', - suggestions: [ - { - desc: `Remove this variable import`, - output: `import {b} from 'b'; console.log(b)`, - }, - ], - }, - ], - }, - { - code: `import a, {b} from 'b'; console.log(a)`, - errors: [errorWithSuggestion(`import a from 'b'; console.log(a)`)], - }, - { - code: `import a, * as c from 'b'; console.log(a)`, - errors: [errorWithSuggestion(`import a from 'b'; console.log(a)`)], - }, - { - code: `import { a } from 'b';`, - errors: 1, - }, - { - code: `import { a, b, c } from 'c';`, - errors: [ - errorWithSuggestion(`import { b, c } from 'c';`), - errorWithSuggestion(`import { a, c } from 'c';`), - errorWithSuggestion(`import { a, b } from 'c';`), - ], - }, - { - code: ` + }, + ], + invalid: [ + { + code: `import a from 'b';`, + errors: [ + { + message: `Remove this unused import of 'a'.`, + line: 1, + endLine: 1, + column: 8, + endColumn: 9, + suggestions: [ + { + desc: `Remove this import statement`, + output: ``, + }, + ], + }, + ], + }, + { + code: `import a, {b} from 'b'; console.log(b)`, + errors: [ + { + messageId: 'removeUnusedImport', + suggestions: [ + { + desc: `Remove this variable import`, + output: `import {b} from 'b'; console.log(b)`, + }, + ], + }, + ], + }, + { + code: `import a, {b} from 'b'; console.log(a)`, + errors: [errorWithSuggestion(`import a from 'b'; console.log(a)`)], + }, + { + code: `import a, * as c from 'b'; console.log(a)`, + errors: [errorWithSuggestion(`import a from 'b'; console.log(a)`)], + }, + { + code: `import { a } from 'b';`, + errors: 1, + }, + { + code: `import { a, b, c } from 'c';`, + errors: [ + errorWithSuggestion(`import { b, c } from 'c';`), + errorWithSuggestion(`import { a, c } from 'c';`), + errorWithSuggestion(`import { a, b } from 'c';`), + ], + }, + { + code: ` import { a, b } from 'c'; console.log(b); `, - errors: 1, - }, - { - code: `import * as a from 'b';`, - errors: 1, - }, - { - code: `import { a as b, c } from 'c'; console.log(c);`, - errors: [errorWithSuggestion(`import { c } from 'c'; console.log(c);`)], - }, - { - code: `import type a from 'b';`, - errors: [errorWithSuggestion('', 'Remove this import statement')], - }, - { - code: `import type { a, b } from 'b'; console.log(b);`, - errors: [errorWithSuggestion(`import type { b } from 'b'; console.log(b);`)], - }, - { - code: ` + errors: 1, + }, + { + code: `import * as a from 'b';`, + errors: 1, + }, + { + code: `import { a as b, c } from 'c'; console.log(c);`, + errors: [errorWithSuggestion(`import { c } from 'c'; console.log(c);`)], + }, + { + code: `import type a from 'b';`, + errors: [errorWithSuggestion('', 'Remove this import statement')], + }, + { + code: `import type { a, b } from 'b'; console.log(b);`, + errors: [errorWithSuggestion(`import type { b } from 'b'; console.log(b);`)], + }, + { + code: ` // comment import Foo from "foo"; import bar from "bar"; bar();`, - errors: [ - errorWithSuggestion( - ` + errors: [ + errorWithSuggestion( + ` // comment import bar from "bar"; bar();`, - 'Remove this import statement', - ), - ], - }, - { - code: `import React, { Component } from 'react';`, - errors: 1, - }, - { - code: `import { jsx } from '@emotion/core'`, - errors: 1, - }, - { - code: ` + 'Remove this import statement', + ), + ], + }, + { + code: `import React, { Component } from 'react';`, + errors: 1, + }, + { + code: `import { jsx } from '@emotion/core'`, + errors: 1, + }, + { + code: ` import { h } from 'some/lib'; // no 'h' jsxFactory export class Component { render() { @@ -300,48 +302,48 @@ bar();`, } } `, - errors: 1, - }, - { - code: `import * as Foo from 'foobar';`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: `import * as Foo from 'foobar';`, + errors: 1, + }, + { + code: ` import * as Foo from 'foobar'; let k: Bar.Foo; `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` import * as Foo from 'foobar'; let k: Baz.Bar.Foo; `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` import * as Foo from 'foobar'; interface I extends Bar.Foo {}; `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` import * as Foo from 'foobar'; class C implements Bar.Foo {}; `, - errors: 1, - }, - ], - }); + errors: 1, + }, + ], + }); - ruleTesterJsxFactory.run('Unused imports denoting jsx factory should be ignored', rule, { - valid: [ - { - filename, - code: ` + ruleTesterJsxFactory.run('Unused imports denoting jsx factory should be ignored', rule, { + valid: [ + { + filename, + code: ` import { h } from 'some/lib'; export class Component { render() { @@ -349,26 +351,26 @@ bar();`, } } `, - }, - { - filename, - code: ` + }, + { + filename, + code: ` import { h } from 'some/lib'; /* does something */ `, - }, - { - filename, - code: ` + }, + { + filename, + code: ` import { Fragment } from 'some/lib'; /* does something */ `, - }, - ], - invalid: [ - { - filename, - code: ` + }, + ], + invalid: [ + { + filename, + code: ` import { g } from 'some/lib'; export class Component { render() { @@ -376,11 +378,11 @@ bar();`, } } `, - errors: 1, - }, - { - filename, - code: ` + errors: 1, + }, + { + filename, + code: ` import { g, h } from 'some/lib'; export class Component { render() { @@ -388,15 +390,15 @@ bar();`, } } `, - errors: 1, - }, - ], - }); + errors: 1, + }, + ], + }); - ruleTesterVue.run('Unnecessary imports should be removed', rule, { - valid: [ - { - code: ` + ruleTesterVue.run('Unnecessary imports should be removed', rule, { + valid: [ + { + code: ` @@ -404,9 +406,9 @@ bar();`, `, - }, - { - code: ` + }, + { + code: ` @@ -414,9 +416,9 @@ bar();`, `, - }, - { - code: ` + }, + { + code: ` @@ -424,9 +426,9 @@ bar();`,
`, - }, - { - code: ` + }, + { + code: ` @@ -434,9 +436,9 @@ bar();`,
`, - }, - { - code: ` + }, + { + code: ` @@ -444,11 +446,11 @@ bar();`, `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` @@ -456,20 +458,21 @@ bar();`,
`, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); -}); -function errorWithSuggestion(output: string, desc = 'Remove this variable import') { - return { - messageId: 'removeUnusedImport', - suggestions: [ - { - desc, - output, - }, - ], - }; -} + function errorWithSuggestion(output: string, desc = 'Remove this variable import') { + return { + messageId: 'removeUnusedImport', + suggestions: [ + { + desc, + output, + }, + ], + }; + } +}); diff --git a/packages/jsts/src/rules/S1134/unit.test.ts b/packages/jsts/src/rules/S1134/unit.test.ts index d40fcfc067..705734dec0 100644 --- a/packages/jsts/src/rules/S1134/unit.test.ts +++ b/packages/jsts/src/rules/S1134/unit.test.ts @@ -16,76 +16,77 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1134', () => { - const ruleTester = new RuleTester(); + it('S1134', () => { + const ruleTester = new RuleTester(); - ruleTester.run('Track uses of FIXME tags', rule, { - valid: [ - { - code: `// Just a regular comment`, - }, - { - code: ` + ruleTester.run('Track uses of FIXME tags', rule, { + valid: [ + { + code: `// Just a regular comment`, + }, + { + code: ` // This is not aFIXME comment // notafixme comment // a fixmeal `, - }, - ], - invalid: [ - { - code: `// FIXME`, - errors: [ - { - message: 'Take the required action to fix the issue indicated by this comment.', - line: 1, - endLine: 1, - column: 4, - endColumn: 9, - }, - ], - }, + }, + ], + invalid: [ + { + code: `// FIXME`, + errors: [ + { + message: 'Take the required action to fix the issue indicated by this comment.', + line: 1, + endLine: 1, + column: 4, + endColumn: 9, + }, + ], + }, - { - code: `/*FIXME Multiline comment + { + code: `/*FIXME Multiline comment FIXME: another fixme (this line is not highlighted) with three fixme */`, - errors: [ - { - message: 'Take the required action to fix the issue indicated by this comment.', - line: 1, - endLine: 1, - column: 3, - endColumn: 8, - }, - { - message: 'Take the required action to fix the issue indicated by this comment.', - line: 2, - endLine: 2, - column: 7, - endColumn: 12, - }, - { - message: 'Take the required action to fix the issue indicated by this comment.', - line: 4, - endLine: 4, - column: 18, - endColumn: 23, - }, - ], - }, - { - code: `// FIXME FIXME`, - errors: 1, - }, - { - code: ` + errors: [ + { + message: 'Take the required action to fix the issue indicated by this comment.', + line: 1, + endLine: 1, + column: 3, + endColumn: 8, + }, + { + message: 'Take the required action to fix the issue indicated by this comment.', + line: 2, + endLine: 2, + column: 7, + endColumn: 12, + }, + { + message: 'Take the required action to fix the issue indicated by this comment.', + line: 4, + endLine: 4, + column: 18, + endColumn: 23, + }, + ], + }, + { + code: `// FIXME FIXME`, + errors: 1, + }, + { + code: ` // FIXME just fix me // FixMe just fix me @@ -112,8 +113,9 @@ describe('S1134', () => { // valid end of file FIXME `, - errors: 11, - }, - ], + errors: 11, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1135/unit.test.ts b/packages/jsts/src/rules/S1135/unit.test.ts index 623c38cc59..8ea522bbd2 100644 --- a/packages/jsts/src/rules/S1135/unit.test.ts +++ b/packages/jsts/src/rules/S1135/unit.test.ts @@ -16,17 +16,18 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1135', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Track uses of TODO tags', rule, { - valid: [ - { - code: `// Just a regular comment`, - }, - { - code: ` + it('S1135', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Track uses of TODO tags', rule, { + valid: [ + { + code: `// Just a regular comment`, + }, + { + code: ` // This is not aTODO comment // notatodo comment @@ -35,64 +36,64 @@ describe('S1135', () => { // método `, - }, - { - code: '// todos', - }, - { - code: '// todos ', - }, - ], - invalid: [ - { - code: `// TODO`, - errors: [ - { - message: 'Complete the task associated to this "TODO" comment.', - line: 1, - endLine: 1, - column: 4, - endColumn: 8, - }, - ], - }, + }, + { + code: '// todos', + }, + { + code: '// todos ', + }, + ], + invalid: [ + { + code: `// TODO`, + errors: [ + { + message: 'Complete the task associated to this "TODO" comment.', + line: 1, + endLine: 1, + column: 4, + endColumn: 8, + }, + ], + }, - { - code: `/*TODO Multiline comment + { + code: `/*TODO Multiline comment TODO: another todo (this line is not highlighted) with three todo */`, - errors: [ - { - message: 'Complete the task associated to this "TODO" comment.', - line: 1, - endLine: 1, - column: 3, - endColumn: 7, - }, - { - message: 'Complete the task associated to this "TODO" comment.', - line: 2, - endLine: 2, - column: 7, - endColumn: 11, - }, - { - message: 'Complete the task associated to this "TODO" comment.', - line: 4, - endLine: 4, - column: 18, - endColumn: 22, - }, - ], - }, - { - code: `// TODO TODO`, - errors: 1, - }, - { - code: ` + errors: [ + { + message: 'Complete the task associated to this "TODO" comment.', + line: 1, + endLine: 1, + column: 3, + endColumn: 7, + }, + { + message: 'Complete the task associated to this "TODO" comment.', + line: 2, + endLine: 2, + column: 7, + endColumn: 11, + }, + { + message: 'Complete the task associated to this "TODO" comment.', + line: 4, + endLine: 4, + column: 18, + endColumn: 22, + }, + ], + }, + { + code: `// TODO TODO`, + errors: 1, + }, + { + code: ` // TODO just do it // Todo just do it @@ -119,8 +120,9 @@ describe('S1135', () => { // valid end of file TODO `, - errors: 11, - }, - ], + errors: 11, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1154/unit.test.ts b/packages/jsts/src/rules/S1154/unit.test.ts index 4a0d3b116a..6f0df3c44a 100644 --- a/packages/jsts/src/rules/S1154/unit.test.ts +++ b/packages/jsts/src/rules/S1154/unit.test.ts @@ -16,85 +16,87 @@ */ import { rule } from './index.js'; import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1154', () => { - const ruleTesterJs = new DefaultParserRuleTester(); - ruleTesterJs.run('Results of operations on strings should not be ignored [js]', rule, { - valid: [ - { - code: ` + it('S1154', () => { + const ruleTesterJs = new DefaultParserRuleTester(); + ruleTesterJs.run('Results of operations on strings should not be ignored [js]', rule, { + valid: [ + { + code: ` let str = 'hello'; str.toUpperCase(); // not raised without type information`, - }, - ], - invalid: [], - }); + }, + ], + invalid: [], + }); - const ruleTesterTs = new RuleTester(); - ruleTesterTs.run(`Results of operations on strings should not be ignored [ts]`, rule, { - valid: [ - { - code: `let res = 'hello'.toUpperCase();`, - }, - { - code: `let res = 'hello'.substr(1, 2).toUpperCase();`, - }, - { - code: ` + const ruleTesterTs = new RuleTester(); + ruleTesterTs.run(`Results of operations on strings should not be ignored [ts]`, rule, { + valid: [ + { + code: `let res = 'hello'.toUpperCase();`, + }, + { + code: `let res = 'hello'.substr(1, 2).toUpperCase();`, + }, + { + code: ` let str = 'hello'; let res = str.toUpperCase(); `, - }, - { - code: `'hello'['whatever']();`, - }, - ], - invalid: [ - { - code: `'hello'.toUpperCase();`, - errors: [ - { - message: `'hello' is an immutable object; you must either store or return the result of the operation.`, - line: 1, - column: 9, - endLine: 1, - endColumn: 20, - }, - ], - }, - { - code: ` + }, + { + code: `'hello'['whatever']();`, + }, + ], + invalid: [ + { + code: `'hello'.toUpperCase();`, + errors: [ + { + message: `'hello' is an immutable object; you must either store or return the result of the operation.`, + line: 1, + column: 9, + endLine: 1, + endColumn: 20, + }, + ], + }, + { + code: ` let str = 'hello'; str.toUpperCase();`, - errors: [ - { - message: `str is an immutable object; you must either store or return the result of the operation.`, - line: 3, - column: 13, - endLine: 3, - endColumn: 24, - }, - ], - }, - { - code: ` + errors: [ + { + message: `str is an immutable object; you must either store or return the result of the operation.`, + line: 3, + column: 13, + endLine: 3, + endColumn: 24, + }, + ], + }, + { + code: ` let str = 'hello'; str.toLowerCase().toUpperCase().toLowerCase();`, - errors: [ - { - message: `String is an immutable object; you must either store or return the result of the operation.`, - line: 3, - column: 41, - endLine: 3, - endColumn: 52, - }, - ], - }, - { - code: `'hello'.substr(1, 2).toUpperCase();`, - errors: 1, - }, - ], + errors: [ + { + message: `String is an immutable object; you must either store or return the result of the operation.`, + line: 3, + column: 41, + endLine: 3, + endColumn: 52, + }, + ], + }, + { + code: `'hello'.substr(1, 2).toUpperCase();`, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S117/unit.test.ts b/packages/jsts/src/rules/S117/unit.test.ts index 2bc13ad781..0b95a7a62d 100644 --- a/packages/jsts/src/rules/S117/unit.test.ts +++ b/packages/jsts/src/rules/S117/unit.test.ts @@ -16,7 +16,7 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTester = new RuleTester(); @@ -24,43 +24,44 @@ const DEFAULT_FORMAT = '^[_$A-Za-z][$A-Za-z0-9]*$|^[_$A-Z][_$A-Z0-9]+$'; const CUSTOM_FORMAT = '^[a-z][a-z0-9]+$'; describe('S117', () => { - ruleTester.run( - 'Local variable and function parameter names should comply with a naming convention', - rule, - { - valid: [ - { - code: ` + it('S117', () => { + ruleTester.run( + 'Local variable and function parameter names should comply with a naming convention', + rule, + { + valid: [ + { + code: ` var foo; let lowerCamelCase; let _leadingUnderScore; let PascalCase; const UPPER_CASE = "UPPER_CASE";`, - options: [{ format: DEFAULT_FORMAT }], - }, - { - code: `let [ foo, [ bar, [ baz, [ qux = quux_quuz, ...corge ] ] ] ] = arr;`, - options: [{ format: DEFAULT_FORMAT }], - }, - { - code: `let { foo, foo_foo, bar: bar, bar_bar: bar, baz: { qux: { quux: Quux, quuz: { corge: Corge = grault_garply, ...waldo } } } } = obj;`, - options: [{ format: DEFAULT_FORMAT }], - }, - { - code: `declare var foo_bar: number // declare are ignored`, - options: [{ format: DEFAULT_FORMAT }], - }, - { - code: ` + options: [{ format: DEFAULT_FORMAT }], + }, + { + code: `let [ foo, [ bar, [ baz, [ qux = quux_quuz, ...corge ] ] ] ] = arr;`, + options: [{ format: DEFAULT_FORMAT }], + }, + { + code: `let { foo, foo_foo, bar: bar, bar_bar: bar, baz: { qux: { quux: Quux, quuz: { corge: Corge = grault_garply, ...waldo } } } } = obj;`, + options: [{ format: DEFAULT_FORMAT }], + }, + { + code: `declare var foo_bar: number // declare are ignored`, + options: [{ format: DEFAULT_FORMAT }], + }, + { + code: ` try {} catch {} try {} catch (foo) {} try {} catch ([ foo ]) {} try {} catch ({ foo: Foo }) {} try {} finally {}`, - options: [{ format: DEFAULT_FORMAT }], - }, - { - code: ` + options: [{ format: DEFAULT_FORMAT }], + }, + { + code: ` declare function f(foo_bar); function f(foo) {} function f(foo = 5) {} @@ -69,77 +70,77 @@ describe('S117', () => { function f({a: foo, b: bar}: {a: number, b: number}) {} foo => foo; let f = function (foo: number) {};`, - options: [{ format: DEFAULT_FORMAT }], - }, - { - code: ` + options: [{ format: DEFAULT_FORMAT }], + }, + { + code: ` let foo = bar_baz`, - options: [{ format: DEFAULT_FORMAT }], - }, - { - code: ` + options: [{ format: DEFAULT_FORMAT }], + }, + { + code: ` let custom; let custom1;`, - options: [{ format: CUSTOM_FORMAT }], - }, - ], - invalid: [ - { - code: `let foo_bar`, - options: [{ format: DEFAULT_FORMAT }], - errors: [ - { - message: `Rename this local variable "foo_bar" to match the regular expression ${DEFAULT_FORMAT}.`, - line: 1, - endLine: 1, - column: 5, - endColumn: 12, - }, - ], - }, - { - code: ` + options: [{ format: CUSTOM_FORMAT }], + }, + ], + invalid: [ + { + code: `let foo_bar`, + options: [{ format: DEFAULT_FORMAT }], + errors: [ + { + message: `Rename this local variable "foo_bar" to match the regular expression ${DEFAULT_FORMAT}.`, + line: 1, + endLine: 1, + column: 5, + endColumn: 12, + }, + ], + }, + { + code: ` var foo_foo; const bar_bar = 5;`, - options: [{ format: DEFAULT_FORMAT }], - errors: [ - error('foo_foo', 'local variable', DEFAULT_FORMAT), - error('bar_bar', 'local variable', DEFAULT_FORMAT), - ], - }, - { - code: `let [ foo_foo, [ bar_bar, [ baz_baz, ...qux_qux ] ] ] = arr;`, - options: [{ format: DEFAULT_FORMAT }], - errors: [ - error('foo_foo', 'local variable', DEFAULT_FORMAT), - error('bar_bar', 'local variable', DEFAULT_FORMAT), - error('baz_baz', 'local variable', DEFAULT_FORMAT), - error('qux_qux', 'local variable', DEFAULT_FORMAT), - ], - }, - { - code: `let { foo, bar: bar_bar, baz: { qux: { quux: quux_quux }, ...corge_corge } } = obj;`, - options: [{ format: DEFAULT_FORMAT }], - errors: [ - error('bar_bar', 'local variable', DEFAULT_FORMAT), - error('quux_quux', 'local variable', DEFAULT_FORMAT), - error('corge_corge', 'local variable', DEFAULT_FORMAT), - ], - }, - { - code: ` + options: [{ format: DEFAULT_FORMAT }], + errors: [ + error('foo_foo', 'local variable', DEFAULT_FORMAT), + error('bar_bar', 'local variable', DEFAULT_FORMAT), + ], + }, + { + code: `let [ foo_foo, [ bar_bar, [ baz_baz, ...qux_qux ] ] ] = arr;`, + options: [{ format: DEFAULT_FORMAT }], + errors: [ + error('foo_foo', 'local variable', DEFAULT_FORMAT), + error('bar_bar', 'local variable', DEFAULT_FORMAT), + error('baz_baz', 'local variable', DEFAULT_FORMAT), + error('qux_qux', 'local variable', DEFAULT_FORMAT), + ], + }, + { + code: `let { foo, bar: bar_bar, baz: { qux: { quux: quux_quux }, ...corge_corge } } = obj;`, + options: [{ format: DEFAULT_FORMAT }], + errors: [ + error('bar_bar', 'local variable', DEFAULT_FORMAT), + error('quux_quux', 'local variable', DEFAULT_FORMAT), + error('corge_corge', 'local variable', DEFAULT_FORMAT), + ], + }, + { + code: ` try {} catch (foo_bar1) {} try {} catch ([ foo_bar2 ]) {} try {} catch ({ foo: foo_bar3 }) {}`, - options: [{ format: DEFAULT_FORMAT }], - errors: [ - error('foo_bar1', 'parameter', DEFAULT_FORMAT), - error('foo_bar2', 'parameter', DEFAULT_FORMAT), - error('foo_bar3', 'parameter', DEFAULT_FORMAT), - ], - }, - { - code: ` + options: [{ format: DEFAULT_FORMAT }], + errors: [ + error('foo_bar1', 'parameter', DEFAULT_FORMAT), + error('foo_bar2', 'parameter', DEFAULT_FORMAT), + error('foo_bar3', 'parameter', DEFAULT_FORMAT), + ], + }, + { + code: ` function f(foo_bar1: number) {} function f(foo_bar2 = 5) {} function f(...foo_bar3: number[]) {} @@ -147,33 +148,33 @@ describe('S117', () => { function f({a: foo_bar6, b: foo_bar7, foo_bar8}: {a: a_a, b: number}) {} foo_bar9 => foo_bar9; let f = function (foo_bar10: number) {};`, - options: [{ format: DEFAULT_FORMAT }], - errors: [ - error('foo_bar1', 'parameter', DEFAULT_FORMAT), - error('foo_bar2', 'parameter', DEFAULT_FORMAT), - error('foo_bar3', 'parameter', DEFAULT_FORMAT), - error('foo_bar4', 'parameter', DEFAULT_FORMAT), - error('foo_bar5', 'parameter', DEFAULT_FORMAT), - error('foo_bar6', 'parameter', DEFAULT_FORMAT), - error('foo_bar7', 'parameter', DEFAULT_FORMAT), - error('foo_bar9', 'parameter', DEFAULT_FORMAT), - error('foo_bar10', 'parameter', DEFAULT_FORMAT), - ], - }, - { - code: ` + options: [{ format: DEFAULT_FORMAT }], + errors: [ + error('foo_bar1', 'parameter', DEFAULT_FORMAT), + error('foo_bar2', 'parameter', DEFAULT_FORMAT), + error('foo_bar3', 'parameter', DEFAULT_FORMAT), + error('foo_bar4', 'parameter', DEFAULT_FORMAT), + error('foo_bar5', 'parameter', DEFAULT_FORMAT), + error('foo_bar6', 'parameter', DEFAULT_FORMAT), + error('foo_bar7', 'parameter', DEFAULT_FORMAT), + error('foo_bar9', 'parameter', DEFAULT_FORMAT), + error('foo_bar10', 'parameter', DEFAULT_FORMAT), + ], + }, + { + code: ` interface i { new(foo_bar1: number); m(foo_bar2: number); }`, - options: [{ format: DEFAULT_FORMAT }], - errors: [ - error('foo_bar1', 'parameter', DEFAULT_FORMAT), - error('foo_bar2', 'parameter', DEFAULT_FORMAT), - ], - }, - { - code: ` + options: [{ format: DEFAULT_FORMAT }], + errors: [ + error('foo_bar1', 'parameter', DEFAULT_FORMAT), + error('foo_bar2', 'parameter', DEFAULT_FORMAT), + ], + }, + { + code: ` class c { "foo_bar": number; // Compliant foo_bar1: number; @@ -181,27 +182,28 @@ describe('S117', () => { m(foo_bar4: number) {} n(foo_bar5: number) }`, - options: [{ format: DEFAULT_FORMAT }], - errors: [ - error('foo_bar1', 'property', DEFAULT_FORMAT), - error('foo_bar2', 'parameter', DEFAULT_FORMAT), - error('foo_bar3', 'parameter', DEFAULT_FORMAT), - error('foo_bar4', 'parameter', DEFAULT_FORMAT), - error('foo_bar5', 'parameter', DEFAULT_FORMAT), - ], - }, - { - code: `let custom_format`, - options: [{ format: CUSTOM_FORMAT }], - errors: [error('custom_format', 'local variable', CUSTOM_FORMAT)], - }, - ], - }, - ); -}); + options: [{ format: DEFAULT_FORMAT }], + errors: [ + error('foo_bar1', 'property', DEFAULT_FORMAT), + error('foo_bar2', 'parameter', DEFAULT_FORMAT), + error('foo_bar3', 'parameter', DEFAULT_FORMAT), + error('foo_bar4', 'parameter', DEFAULT_FORMAT), + error('foo_bar5', 'parameter', DEFAULT_FORMAT), + ], + }, + { + code: `let custom_format`, + options: [{ format: CUSTOM_FORMAT }], + errors: [error('custom_format', 'local variable', CUSTOM_FORMAT)], + }, + ], + }, + ); + }); -function error(symbol: string, symbolType: string, format: string) { - return { - message: `Rename this ${symbolType} "${symbol}" to match the regular expression ${format}.`, - }; -} + function error(symbol: string, symbolType: string, format: string) { + return { + message: `Rename this ${symbolType} "${symbol}" to match the regular expression ${format}.`, + }; + } +}); diff --git a/packages/jsts/src/rules/S1192/unit.test.ts b/packages/jsts/src/rules/S1192/unit.test.ts index 7a684a8705..799832725d 100644 --- a/packages/jsts/src/rules/S1192/unit.test.ts +++ b/packages/jsts/src/rules/S1192/unit.test.ts @@ -16,117 +16,118 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1192', () => { - const ruleTester = new RuleTester(); + it('S1192', () => { + const ruleTester = new RuleTester(); - ruleTester.run('S1192', rule, { - valid: [ - { - code: ` + ruleTester.run('S1192', rule, { + valid: [ + { + code: ` console.log("some message"); console.log("some message"); console.log('some message');`, - options: [{ threshold: 4 }], - }, - { - code: ` // too small + options: [{ threshold: 4 }], + }, + { + code: ` // too small console.log("a&b"); console.log("a&b"); console.log("a&b");`, - }, - { - code: ` // too small when trimmed + }, + { + code: ` // too small when trimmed // trimming allows to not raise issue for flowtype whitespaces // which are created as literals for some reason console.log(" a "); console.log(" a "); console.log(" a ");`, - }, - { - code: ` // numbers + }, + { + code: ` // numbers console.log(12345.67890); console.log(12345.67890); console.log(12345.67890);`, - }, - { - code: ` + }, + { + code: ` console.log("only 2 times"); console.log("only 2 times");`, - }, - { - code: `// no separators + }, + { + code: `// no separators console.log("stringstring"); console.log("stringstring"); console.log("stringstring"); console.log("stringstring");`, - }, - { - code: `// ImportDeclaration + }, + { + code: `// ImportDeclaration import defaultExport1 from "module-name-long"; import defaultExport2 from "module-name-long"; import defaultExport3 from "module-name-long"; `, - }, - { - code: ` // ImportDeclaration + }, + { + code: ` // ImportDeclaration import name1 from "module-name-long"; import name2 from "module-name-long"; import name3 from "module-name-long"; `, - }, - { - code: ` // ImportDeclaration + }, + { + code: ` // ImportDeclaration import "module-name-long"; import "module-name-long"; import "module-name-long"; `, - }, - { - code: ` // ImportExpression + }, + { + code: ` // ImportExpression import("module-name-long"); import("module-name-long"); import("module-name-long"); `, - }, - { - code: `// ExportAllDeclaration + }, + { + code: `// ExportAllDeclaration export * from "module-name-long"; export * from "module-name-long"; export * from "module-name-long"; `, - }, - { - code: `// CallExpression 'require' + }, + { + code: `// CallExpression 'require' const a = require("module-name-long").a; const b = require("module-name-long").b; const c = require("module-name-long").c; `, - }, - { - code: `// ExportNamedDeclaration + }, + { + code: `// ExportNamedDeclaration export { a } from "module-name-long"; export { b } from "module-name-long"; export { c } from "module-name-long"; `, - }, - { - code: ` // JSXAttribute + }, + { + code: ` // JSXAttribute ; ; ; ; `, - }, - { - code: ` + }, + { + code: ` console.log(\`some message\`); console.log('some message'); console.log("some message");`, - }, - { - code: ` + }, + { + code: ` const obj1 = { "some property": 1 }; @@ -136,109 +137,109 @@ describe('S1192', () => { const obj3 = { "some property": 1 };`, - }, - { - code: ` + }, + { + code: ` 'use strict'; 'use strict'; 'use strict'; `, - }, - { - code: ` + }, + { + code: ` let x: 'Hello world'; function foo(arg: 'Hello world'): 'Hello world' { return 'Hello world'; } `, - }, - { - code: ` + }, + { + code: ` 'application/json'; 'application/json'; 'application/json';; `, - }, - { - code: ` + }, + { + code: ` console.log('Hello world!'); console.log('Hello world!'); console.log('Hello world!'); `, - options: [{ threshold: 2, ignoreStrings: 'Hello world!' }, 'sonar-runtime'], - }, - ], - invalid: [ - { - code: ` + options: [{ threshold: 2, ignoreStrings: 'Hello world!' }, 'sonar-runtime'], + }, + ], + invalid: [ + { + code: ` console.log("some message"); console.log("some message"); console.log('some message');`, - errors: [ - { - message: 'Define a constant instead of duplicating this literal 3 times.', - column: 17, - endColumn: 31, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Define a constant instead of duplicating this literal 3 times.', + column: 17, + endColumn: 31, + }, + ], + }, + { + code: ` console.log("some message"); console.log('some message');`, - errors: [ - { - messageId: 'sonarRuntime', - data: { - sonarRuntimeData: JSON.stringify({ - message: 'Define a constant instead of duplicating this literal 2 times.', - secondaryLocations: [ - { - message: 'Duplication', - column: 16, - line: 3, - endColumn: 30, - endLine: 3, - }, - ], - }), + errors: [ + { + messageId: 'sonarRuntime', + data: { + sonarRuntimeData: JSON.stringify({ + message: 'Define a constant instead of duplicating this literal 2 times.', + secondaryLocations: [ + { + message: 'Duplication', + column: 16, + line: 3, + endColumn: 30, + endLine: 3, + }, + ], + }), + }, + line: 2, + endLine: 2, + column: 17, + endColumn: 31, }, - line: 2, - endLine: 2, - column: 17, - endColumn: 31, - }, - ], - options: [{ threshold: 2 }, 'sonar-runtime'], - }, - { - code: ` + ], + options: [{ threshold: 2 }, 'sonar-runtime'], + }, + { + code: ` ; ; ; let x = "some-string", y = "some-string", z = "some-string"; `, - errors: [ - { - message: 'Define a constant instead of duplicating this literal 3 times.', - line: 5, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Define a constant instead of duplicating this literal 3 times.', + line: 5, + }, + ], + }, + { + code: ` console.log("some message"); console.log('some message');`, - errors: [ - { - message: 'Define a constant instead of duplicating this literal 2 times.', - line: 2, - }, - ], - options: [{ threshold: 2 }], - }, - { - code: ` + errors: [ + { + message: 'Define a constant instead of duplicating this literal 2 times.', + line: 2, + }, + ], + options: [{ threshold: 2 }], + }, + { + code: ` const obj1 = { key: "some message" }; @@ -248,13 +249,14 @@ describe('S1192', () => { const obj3 = { key: "some message" };`, - errors: [ - { - message: 'Define a constant instead of duplicating this literal 3 times.', - line: 3, - }, - ], - }, - ], + errors: [ + { + message: 'Define a constant instead of duplicating this literal 3 times.', + line: 3, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1219/unit.test.ts b/packages/jsts/src/rules/S1219/unit.test.ts index 0ee8a0f6e5..056e816ea9 100644 --- a/packages/jsts/src/rules/S1219/unit.test.ts +++ b/packages/jsts/src/rules/S1219/unit.test.ts @@ -16,28 +16,29 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1219', () => { - const ruleTester = new RuleTester(); - ruleTester.run(`"switch" statements should not contain non-case labels`, rule, { - valid: [ - { - code: ` + it('S1219', () => { + const ruleTester = new RuleTester(); + ruleTester.run(`"switch" statements should not contain non-case labels`, rule, { + valid: [ + { + code: ` switch (k) { case 0: case 1: break; } `, - }, - { - code: ` + }, + { + code: ` l: while (b) {} `, - }, - { - code: ` + }, + { + code: ` switch (k) { case 0: case 1: @@ -46,9 +47,9 @@ describe('S1219', () => { } } `, - }, - { - code: ` + }, + { + code: ` switch (k) { case 0: case 1: @@ -57,29 +58,29 @@ describe('S1219', () => { } } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` switch (k) { case 0: case 1: l: while (b) {} } `, - errors: [ - { - message: `Remove this misleading "l" label.`, - line: 5, - endLine: 5, - column: 11, - endColumn: 12, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Remove this misleading "l" label.`, + line: 5, + endLine: 5, + column: 11, + endColumn: 12, + }, + ], + }, + { + code: ` switch (k) { case 0: case 1: @@ -88,10 +89,10 @@ describe('S1219', () => { } } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` switch (k) { case 0: case 1: @@ -102,10 +103,10 @@ describe('S1219', () => { } } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` switch (k) { case 0: case 1: @@ -117,8 +118,9 @@ describe('S1219', () => { } } `, - errors: 2, - }, - ], + errors: 2, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1226/unit.test.ts b/packages/jsts/src/rules/S1226/unit.test.ts index 9ce1038707..5f3d43049d 100644 --- a/packages/jsts/src/rules/S1226/unit.test.ts +++ b/packages/jsts/src/rules/S1226/unit.test.ts @@ -16,40 +16,41 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1226', () => { - const ruleTester = new RuleTester(); + it('S1226', () => { + const ruleTester = new RuleTester(); - const NON_COMPLIANT_REGEX = /\/\/\sNoncompliant\s{{(\w+)}}/; - function invalidTest(code: string) { - const errors = code.split('\n').reduce((accumulator, currentLine, index) => { - const res = NON_COMPLIANT_REGEX.exec(currentLine); - if (res && res[1]) { - const currentLine = index + 1; - accumulator.push({ - message: - `Introduce a new variable or use its initial value ` + - `before reassigning "${res[1]}".`, - line: currentLine, - endLine: currentLine, - }); - } - return accumulator; - }, []); - return { - code, - errors, - }; - } + const NON_COMPLIANT_REGEX = /\/\/\sNoncompliant\s{{(\w+)}}/; + function invalidTest(code: string) { + const errors = code.split('\n').reduce((accumulator, currentLine, index) => { + const res = NON_COMPLIANT_REGEX.exec(currentLine); + if (res && res[1]) { + const currentLine = index + 1; + accumulator.push({ + message: + `Introduce a new variable or use its initial value ` + + `before reassigning "${res[1]}".`, + line: currentLine, + endLine: currentLine, + }); + } + return accumulator; + }, []); + return { + code, + errors, + }; + } - ruleTester.run( - "Function parameters, caught exceptions and foreach variables' initial values should not be ignored", - rule, - { - valid: [ - { - code: ` + ruleTester.run( + "Function parameters, caught exceptions and foreach variables' initial values should not be ignored", + rule, + { + valid: [ + { + code: ` function foo(p1, p2, p3, ... p4) { p1.prop1 = 42; foo(p2, p3); @@ -164,9 +165,9 @@ describe('S1226', () => { MyClass.prototype.functionToCall.apply(this, arguments); p1 = this.position; }`, - }, - { - code: ` + }, + { + code: ` function someFunction(node, param = false) { switch (node.type) { case 'ForStatement': @@ -182,55 +183,57 @@ describe('S1226', () => { } node.children().forEach(child => someFunction(child, param)); }`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function foo(p1) { p1 = 42; }`, - errors: [ - { - message: 'Introduce a new variable or use its initial value before reassigning "p1".', - line: 3, - endLine: 3, - column: 11, - endColumn: 18, - }, - ], - }, - { - code: ` + errors: [ + { + message: + 'Introduce a new variable or use its initial value before reassigning "p1".', + line: 3, + endLine: 3, + column: 11, + endColumn: 18, + }, + ], + }, + { + code: ` function foo(p1) { while (someBoolean) { if (p1 = doSomething()) return p1; } }`, - errors: [ - { - message: 'Introduce a new variable or use its initial value before reassigning "p1".', - line: 4, - endLine: 4, - column: 17, - endColumn: 35, - }, - ], - }, - invalidTest(` + errors: [ + { + message: + 'Introduce a new variable or use its initial value before reassigning "p1".', + line: 4, + endLine: 4, + column: 17, + endColumn: 35, + }, + ], + }, + invalidTest(` function foo(p1) { if (someBoolean) { p1 = "defaultValue"; } p1 = "newValue"; // Noncompliant {{p1}} }`), - invalidTest(` + invalidTest(` function foo(p1) { while (someBoolean) { p1 = "defaultValue"; // Noncompliant {{p1}} } }`), - invalidTest(` + invalidTest(` function bindingElements({a: p1 = 1, p2 = 2}, [p3 = 3, p4 = 4], p5 = 5) { p1 = 42; // Noncompliant {{p1}} p2 = 42; // Noncompliant {{p2}} @@ -239,7 +242,7 @@ describe('S1226', () => { p5 = 42; // Noncompliant {{p5}} p5 = 42; }`), - invalidTest(` + invalidTest(` var arrow_function1 = (p1, p2) => { p2 = 42; // Noncompliant {{p2}} p1.prop1 = 42; @@ -254,7 +257,7 @@ describe('S1226', () => { (function(p1) { p1 = 42; // Noncompliant {{p1}} })(1);`), - invalidTest(` + invalidTest(` try { foo(); } catch (e) { @@ -268,7 +271,7 @@ describe('S1226', () => { e1 = foo(); // Noncompliant {{e1}} foo(e2); }`), - invalidTest(` + invalidTest(` for (var x in obj) { for (let x in obj) { x = foo(); // Noncompliant {{x}} @@ -308,7 +311,7 @@ describe('S1226', () => { a = foo(); // Noncompliant {{a}} b = foo(); // Noncompliant {{b}} }`), - invalidTest(` + invalidTest(` function foo(p1, p2) { var p1Copied = p1; for (var [forParam1, forParam2] in myArray) { @@ -326,7 +329,7 @@ describe('S1226', () => { } } }`), - invalidTest(` + invalidTest(` function foo() { const argumentsIsRead = arguments[0]; } @@ -334,7 +337,7 @@ describe('S1226', () => { function bar(p1) { p1 = 3; // Noncompliant {{p1}} }`), - invalidTest(` + invalidTest(` function f1(p1) { function f2(p2) { var args = arguments[0]; @@ -345,7 +348,8 @@ describe('S1226', () => { } } }`), - ], - }, - ); + ], + }, + ); + }); }); diff --git a/packages/jsts/src/rules/S124/unit.test.ts b/packages/jsts/src/rules/S124/unit.test.ts index 3d69dbbc5d..1b7724aeb7 100644 --- a/packages/jsts/src/rules/S124/unit.test.ts +++ b/packages/jsts/src/rules/S124/unit.test.ts @@ -16,7 +16,7 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTester = new RuleTester(); @@ -24,111 +24,113 @@ const optionsWithouthMessage = [{ regularExpression: '[a-z]' }]; const optionsWithMessage = [{ regularExpression: '[a-z]', message: 'this is a message' }]; describe('S124', () => { - ruleTester.run('Track comments matching a regular expression', rule, { - valid: [ - { - code: ` + it('S124', () => { + ruleTester.run('Track comments matching a regular expression', rule, { + valid: [ + { + code: ` // No options means that no comment are reported. `, - }, - { - code: ` + }, + { + code: ` // THE COMMENT DO NOT MATCH THE REGEX `, - options: optionsWithMessage, - }, - { - code: ` + options: optionsWithMessage, + }, + { + code: ` // THE COMMENT DO NOT MATCH THE REGEX `, - options: optionsWithouthMessage, - }, - ], - invalid: [ - { - code: `// options with a message!`, - options: optionsWithMessage, - errors: [ - { - message: 'this is a message', - line: 1, - endLine: 1, - column: 1, - endColumn: 27, - }, - ], - }, - { - code: `// options without a message!`, - options: optionsWithouthMessage, - errors: [ - { - message: 'The regular expression matches this comment.', - line: 1, - endLine: 1, - column: 1, - endColumn: 30, - }, - ], - }, - { - code: `// Hello, World! This will not work for case-sensitive lowercase.`, - options: [{ regularExpression: 'world', message: 'flag-i', flags: 'i' }], - errors: [ - { - message: 'flag-i', - line: 1, - endLine: 1, - column: 1, - endColumn: 66, - }, - ], - }, - { - code: `// start\uD83D\uDE00\uD83D\uDE00end; This will not work without unicode flag`, - options: [{ regularExpression: 'start.{2}end', message: 'flag-u', flags: 'u' }], - errors: [ - { - message: 'flag-u', - line: 1, - endLine: 1, - column: 1, - endColumn: 57, - }, - ], - }, - { - code: `// start\uD83D\uDE00aBcDend; This requires both unicode and case insensitivity.`, - options: [{ regularExpression: 'start.{1}ABCDend', message: 'flags-ui', flags: 'ui' }], - errors: [ - { - message: 'flags-ui', - line: 1, - endLine: 1, - column: 1, - endColumn: 70, - }, - ], - }, - { - code: `// The flag option is quite robust against invalid inputs: TEST.`, - options: [ - { - regularExpression: 'test', - message: 'flags-invalid-(?i)', - flags: '(?i)', - }, - ], - errors: [ - { - message: 'flags-invalid-(?i)', - line: 1, - endLine: 1, - column: 1, - endColumn: 65, - }, - ], - }, - ], + options: optionsWithouthMessage, + }, + ], + invalid: [ + { + code: `// options with a message!`, + options: optionsWithMessage, + errors: [ + { + message: 'this is a message', + line: 1, + endLine: 1, + column: 1, + endColumn: 27, + }, + ], + }, + { + code: `// options without a message!`, + options: optionsWithouthMessage, + errors: [ + { + message: 'The regular expression matches this comment.', + line: 1, + endLine: 1, + column: 1, + endColumn: 30, + }, + ], + }, + { + code: `// Hello, World! This will not work for case-sensitive lowercase.`, + options: [{ regularExpression: 'world', message: 'flag-i', flags: 'i' }], + errors: [ + { + message: 'flag-i', + line: 1, + endLine: 1, + column: 1, + endColumn: 66, + }, + ], + }, + { + code: `// start\uD83D\uDE00\uD83D\uDE00end; This will not work without unicode flag`, + options: [{ regularExpression: 'start.{2}end', message: 'flag-u', flags: 'u' }], + errors: [ + { + message: 'flag-u', + line: 1, + endLine: 1, + column: 1, + endColumn: 57, + }, + ], + }, + { + code: `// start\uD83D\uDE00aBcDend; This requires both unicode and case insensitivity.`, + options: [{ regularExpression: 'start.{1}ABCDend', message: 'flags-ui', flags: 'ui' }], + errors: [ + { + message: 'flags-ui', + line: 1, + endLine: 1, + column: 1, + endColumn: 70, + }, + ], + }, + { + code: `// The flag option is quite robust against invalid inputs: TEST.`, + options: [ + { + regularExpression: 'test', + message: 'flags-invalid-(?i)', + flags: '(?i)', + }, + ], + errors: [ + { + message: 'flags-invalid-(?i)', + line: 1, + endLine: 1, + column: 1, + endColumn: 65, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S125/unit.test.ts b/packages/jsts/src/rules/S125/unit.test.ts index 64a768314c..ae729efa57 100644 --- a/packages/jsts/src/rules/S125/unit.test.ts +++ b/packages/jsts/src/rules/S125/unit.test.ts @@ -16,14 +16,15 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S125', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Sections of code should not be commented out', rule, { - valid: [ - { - code: ` + it('S125', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Sections of code should not be commented out', rule, { + valid: [ + { + code: ` // // @@ -114,58 +115,58 @@ describe('S125', () => { // } `, - }, - { - // FN since 2-step implementation - code: ` + }, + { + // FN since 2-step implementation + code: ` // return foo().bar() `, - }, - { - // FN since 2-step implementation - code: ` + }, + { + // FN since 2-step implementation + code: ` // throw foo().bar() `, - }, - { - // FN since 2-step implementation - code: ` + }, + { + // FN since 2-step implementation + code: ` // YUI().use('*'); // Comment following ';' `, - }, - ], - invalid: [ - { - code: `// if (something) {}`, - errors: [ - { - message: 'Remove this commented out code.', - line: 1, - endLine: 1, - column: 1, - endColumn: 21, - suggestions: [{ desc: 'Remove this commented out code', output: '' }], - }, - ], - }, - { - code: `// // nested comment + }, + ], + invalid: [ + { + code: `// if (something) {}`, + errors: [ + { + message: 'Remove this commented out code.', + line: 1, + endLine: 1, + column: 1, + endColumn: 21, + suggestions: [{ desc: 'Remove this commented out code', output: '' }], + }, + ], + }, + { + code: `// // nested comment // foo(a, function(){ // doSmth(); // });`, - errors: [ - { - message: 'Remove this commented out code.', - line: 1, - column: 1, - endLine: 4, - endColumn: 7, - suggestions: [{ desc: 'Remove this commented out code', output: '' }], - }, - ], - }, - { - code: `/* // nested comment + errors: [ + { + message: 'Remove this commented out code.', + line: 1, + column: 1, + endLine: 4, + endColumn: 7, + suggestions: [{ desc: 'Remove this commented out code', output: '' }], + }, + ], + }, + { + code: `/* // nested comment @annotation class MyClass {} @@ -173,139 +174,140 @@ foo(a, function(){ doSmth(); const a = });*/`, - errors: [ - { - message: 'Remove this commented out code.', - line: 1, - column: 1, - endLine: 8, - endColumn: 6, - suggestions: [{ desc: 'Remove this commented out code', output: '' }], - }, - ], - }, - { - code: `// return foo().bar();`, - errors: [ - { - messageId: 'commentedCode', - suggestions: [{ desc: 'Remove this commented out code', output: '' }], - }, - ], - }, - { - code: `// foo(); + errors: [ + { + message: 'Remove this commented out code.', + line: 1, + column: 1, + endLine: 8, + endColumn: 6, + suggestions: [{ desc: 'Remove this commented out code', output: '' }], + }, + ], + }, + { + code: `// return foo().bar();`, + errors: [ + { + messageId: 'commentedCode', + suggestions: [{ desc: 'Remove this commented out code', output: '' }], + }, + ], + }, + { + code: `// foo(); // bar();`, - errors: [ - { - messageId: 'commentedCode', - suggestions: [{ desc: 'Remove this commented out code', output: '' }], - }, - ], - }, - { - code: `/* foo(); + errors: [ + { + messageId: 'commentedCode', + suggestions: [{ desc: 'Remove this commented out code', output: '' }], + }, + ], + }, + { + code: `/* foo(); bar(); */ const a = 1;`, - errors: [ - { - messageId: 'commentedCode', - suggestions: [ - { - desc: 'Remove this commented out code', - output: ` + errors: [ + { + messageId: 'commentedCode', + suggestions: [ + { + desc: 'Remove this commented out code', + output: ` const a = 1;`, - }, - ], - }, - ], - }, - { - code: `/* throw foo().bar(); */`, - errors: [ - { - messageId: 'commentedCode', - suggestions: [{ desc: 'Remove this commented out code', output: '' }], - }, - ], - }, - { - code: `// if (condition) { + }, + ], + }, + ], + }, + { + code: `/* throw foo().bar(); */`, + errors: [ + { + messageId: 'commentedCode', + suggestions: [{ desc: 'Remove this commented out code', output: '' }], + }, + ], + }, + { + code: `// if (condition) { // while (condition) { // doSomething();`, - errors: [ - { - messageId: 'commentedCode', - suggestions: [{ desc: 'Remove this commented out code', output: '' }], - }, - ], - }, - { - code: `// while (condition) { + errors: [ + { + messageId: 'commentedCode', + suggestions: [{ desc: 'Remove this commented out code', output: '' }], + }, + ], + }, + { + code: `// while (condition) { // doSomething(); // } // }`, - errors: [ - { - messageId: 'commentedCode', - suggestions: [{ desc: 'Remove this commented out code', output: '' }], - }, - ], - }, - { - code: `// }}`, - errors: [ - { - messageId: 'commentedCode', - suggestions: [{ desc: 'Remove this commented out code', output: '' }], - }, - ], - }, - { - code: `// {{`, - errors: [ - { - messageId: 'commentedCode', - suggestions: [{ desc: 'Remove this commented out code', output: '' }], - }, - ], - }, - { - code: `// } + errors: [ + { + messageId: 'commentedCode', + suggestions: [{ desc: 'Remove this commented out code', output: '' }], + }, + ], + }, + { + code: `// }}`, + errors: [ + { + messageId: 'commentedCode', + suggestions: [{ desc: 'Remove this commented out code', output: '' }], + }, + ], + }, + { + code: `// {{`, + errors: [ + { + messageId: 'commentedCode', + suggestions: [{ desc: 'Remove this commented out code', output: '' }], + }, + ], + }, + { + code: `// } // }`, - errors: [ - { - messageId: 'commentedCode', - suggestions: [{ desc: 'Remove this commented out code', output: '' }], - }, - ], - }, - { - code: `let x = /* let x = 42; */ 0;`, - errors: [ - { - messageId: 'commentedCode', - suggestions: [{ desc: 'Remove this commented out code', output: `let x = 0;` }], - }, - ], - }, - { - code: `// if (value == 42) { + errors: [ + { + messageId: 'commentedCode', + suggestions: [{ desc: 'Remove this commented out code', output: '' }], + }, + ], + }, + { + code: `let x = /* let x = 42; */ 0;`, + errors: [ + { + messageId: 'commentedCode', + suggestions: [{ desc: 'Remove this commented out code', output: `let x = 0;` }], + }, + ], + }, + { + code: `// if (value == 42) { // value++ let x = 0;`, - errors: [ - { - messageId: 'commentedCode', - suggestions: [ - { - desc: 'Remove this commented out code', - output: ` + errors: [ + { + messageId: 'commentedCode', + suggestions: [ + { + desc: 'Remove this commented out code', + output: ` let x = 0;`, - }, - ], - }, - ], - }, - ], + }, + ], + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S126/unit.test.ts b/packages/jsts/src/rules/S126/unit.test.ts index 4ba714ed2e..c9d297e799 100644 --- a/packages/jsts/src/rules/S126/unit.test.ts +++ b/packages/jsts/src/rules/S126/unit.test.ts @@ -16,44 +16,45 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTester = new RuleTester(); describe('S126', () => { - ruleTester.run(`"if ... else if" constructs should end with "else" clauses`, rule, { - valid: [ - { - code: ` + it('S126', () => { + ruleTester.run(`"if ... else if" constructs should end with "else" clauses`, rule, { + valid: [ + { + code: ` if (x == 0) { x = 42; } `, - }, - { - code: ` + }, + { + code: ` if (x == 0) x = 42; `, - }, - { - code: ` + }, + { + code: ` if (x == 0) { x = 42; } else { x = -42; } `, - }, - { - code: ` + }, + { + code: ` if (x == 0) x = 42; else x = -42; `, - }, - { - code: ` + }, + { + code: ` if (x == 0) { x == 42; } else { @@ -62,11 +63,11 @@ describe('S126', () => { } } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` if (x == 0) { x = 42; } else if (x == 1) { @@ -75,34 +76,35 @@ describe('S126', () => { x = 0; } `, - errors: [ - { - messageId: 'addMissingElseClause', - line: 6, - endLine: 6, - column: 9, - endColumn: 16, - }, - ], - }, - { - code: ` + errors: [ + { + messageId: 'addMissingElseClause', + line: 6, + endLine: 6, + column: 9, + endColumn: 16, + }, + ], + }, + { + code: ` if (x == 0) x == 42; else if (x == 1) x == -42; `, - errors: [ - { - messageId: 'addMissingElseClause', - line: 4, - endLine: 5, - column: 7, - endColumn: 11, - }, - ], - }, - ], + errors: [ + { + messageId: 'addMissingElseClause', + line: 4, + endLine: 5, + column: 7, + endColumn: 11, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1264/unit.test.ts b/packages/jsts/src/rules/S1264/unit.test.ts index 28517d3c77..2d0e783d5d 100644 --- a/packages/jsts/src/rules/S1264/unit.test.ts +++ b/packages/jsts/src/rules/S1264/unit.test.ts @@ -16,45 +16,47 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1264', () => { - const ruleTester = new RuleTester(); + it('S1264', () => { + const ruleTester = new RuleTester(); - const message = 'replaceForWithWhileLoop'; + const message = 'replaceForWithWhileLoop'; - ruleTester.run('prefer-while', rule, { - valid: [ - { code: 'for(var i = 0; condition;) { }' }, - { code: 'for(var i = 0; condition; i++) { }' }, - { code: 'for(var i = 0;; i++) { }' }, - { code: 'for (i; condition; ) { }' }, - { code: 'for ( ; i < length; i++ ) { }' }, - { code: 'while (i < length) { }' }, - { code: 'for (a in b) { }' }, - { code: 'for (a of b) { }' }, - { code: 'for(;;) {}' }, - ], - invalid: [ - { - code: 'for(;condition;) {}', - errors: [{ messageId: message, line: 1, column: 1, endColumn: 4 }], - output: 'while (condition) {}', - }, - { - code: 'for (;condition; ) foo();', - errors: [{ messageId: message }], - output: 'while (condition) foo();', - }, - { - code: ` + ruleTester.run('prefer-while', rule, { + valid: [ + { code: 'for(var i = 0; condition;) { }' }, + { code: 'for(var i = 0; condition; i++) { }' }, + { code: 'for(var i = 0;; i++) { }' }, + { code: 'for (i; condition; ) { }' }, + { code: 'for ( ; i < length; i++ ) { }' }, + { code: 'while (i < length) { }' }, + { code: 'for (a in b) { }' }, + { code: 'for (a of b) { }' }, + { code: 'for(;;) {}' }, + ], + invalid: [ + { + code: 'for(;condition;) {}', + errors: [{ messageId: message, line: 1, column: 1, endColumn: 4 }], + output: 'while (condition) {}', + }, + { + code: 'for (;condition; ) foo();', + errors: [{ messageId: message }], + output: 'while (condition) foo();', + }, + { + code: ` for(;i < 10;) doSomething();`, - errors: [{ messageId: message }], - output: ` + errors: [{ messageId: message }], + output: ` while (i < 10) doSomething();`, - }, - ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S128/unit.test.ts b/packages/jsts/src/rules/S128/unit.test.ts index e7d1cd82c6..3b34ec412f 100644 --- a/packages/jsts/src/rules/S128/unit.test.ts +++ b/packages/jsts/src/rules/S128/unit.test.ts @@ -16,14 +16,15 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S128', () => { - const ruleTester = new RuleTester(); - ruleTester.run('No fallthrough in switch statement', rule, { - valid: [ - { - code: ` + it('S128', () => { + const ruleTester = new RuleTester(); + ruleTester.run('No fallthrough in switch statement', rule, { + valid: [ + { + code: ` switch (x) { case 0: process.exit(1); @@ -31,9 +32,9 @@ describe('S128', () => { doSomething(); } `, - }, - { - code: ` + }, + { + code: ` switch (x) { case 0: if (foo()) { @@ -47,9 +48,9 @@ describe('S128', () => { doSomething(); } `, - }, - { - code: ` + }, + { + code: ` switch (x) { case 0: if (foo()) { @@ -66,9 +67,9 @@ describe('S128', () => { doSomething(); } `, - }, - { - code: ` + }, + { + code: ` switch (param) {} // with not executable clause @@ -93,9 +94,9 @@ describe('S128', () => { break; } `, - }, - { - code: ` + }, + { + code: ` switch ( x ) { case 0: while ( isTrue() ) { @@ -106,11 +107,11 @@ describe('S128', () => { console.log("hello"); } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function func(){ while(condition) { switch (param) { @@ -130,30 +131,30 @@ describe('S128', () => { } } }`, - errors: [ - { - message: - 'End this switch case with an unconditional break, continue, return or throw statement.', - line: 12, - column: 13, - endLine: 12, - endColumn: 17, - }, - ], - }, + errors: [ + { + message: + 'End this switch case with an unconditional break, continue, return or throw statement.', + line: 12, + column: 13, + endLine: 12, + endColumn: 17, + }, + ], + }, - { - code: ` + { + code: ` switch (param) { default: // Noncompliant doSomething(); case 0: // OK doSomethingElse(); }`, - errors: [{ messageId: 'switchEnd', line: 3 }], - }, - { - code: ` + errors: [{ messageId: 'switchEnd', line: 3 }], + }, + { + code: ` function fun() { switch (param) { case 0: // OK @@ -174,13 +175,13 @@ describe('S128', () => { } } `, - errors: [ - { messageId: 'switchEnd', line: 8 }, - { messageId: 'switchEnd', line: 10 }, - ], - }, - { - code: ` + errors: [ + { messageId: 'switchEnd', line: 8 }, + { messageId: 'switchEnd', line: 10 }, + ], + }, + { + code: ` function fun(){ switch (param) { case a: @@ -213,10 +214,10 @@ describe('S128', () => { } } `, - errors: [{ messageId: 'switchEnd', line: 19 }], - }, - { - code: ` + errors: [{ messageId: 'switchEnd', line: 19 }], + }, + { + code: ` function fun() { switch (param) { case 0: // Noncompliant @@ -228,10 +229,10 @@ describe('S128', () => { } } `, - errors: [{ messageId: 'switchEnd', line: 4 }], - }, - { - code: ` + errors: [{ messageId: 'switchEnd', line: 4 }], + }, + { + code: ` function fun() { // OK with comment switch (x) { @@ -275,10 +276,10 @@ describe('S128', () => { } } `, - errors: [{ messageId: 'switchEnd', line: 35 }], - }, - { - code: ` + errors: [{ messageId: 'switchEnd', line: 35 }], + }, + { + code: ` switch (x) { case 0: if (foo()) { @@ -288,10 +289,10 @@ describe('S128', () => { doSomething(); } `, - errors: [{ messageId: 'switchEnd', line: 3 }], - }, - { - code: ` + errors: [{ messageId: 'switchEnd', line: 3 }], + }, + { + code: ` switch (x) { case 0: if (foo()) { @@ -302,10 +303,10 @@ describe('S128', () => { doSomething(); } `, - errors: [{ messageId: 'switchEnd', line: 3 }], - }, - { - code: ` + errors: [{ messageId: 'switchEnd', line: 3 }], + }, + { + code: ` process.exit(1); switch (x) { case 0: @@ -314,10 +315,10 @@ describe('S128', () => { doSomethingElse(); } `, - errors: [{ messageId: 'switchEnd', line: 4 }], - }, - { - code: ` + errors: [{ messageId: 'switchEnd', line: 4 }], + }, + { + code: ` switch (x) { case 0: doSomething(); @@ -332,10 +333,10 @@ describe('S128', () => { } `, - errors: [{ messageId: 'switchEnd', line: 9 }], - }, - { - code: ` + errors: [{ messageId: 'switchEnd', line: 9 }], + }, + { + code: ` function doSomething() { doSmth(); } @@ -348,11 +349,12 @@ describe('S128', () => { doSomethingElse(); } `, - errors: [ - { messageId: 'switchEnd', line: 6 }, - { messageId: 'switchEnd', line: 8 }, - ], - }, - ], + errors: [ + { messageId: 'switchEnd', line: 6 }, + { messageId: 'switchEnd', line: 8 }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1291/unit.test.ts b/packages/jsts/src/rules/S1291/unit.test.ts index 0d449df9dd..ab69804a78 100644 --- a/packages/jsts/src/rules/S1291/unit.test.ts +++ b/packages/jsts/src/rules/S1291/unit.test.ts @@ -16,62 +16,64 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1291', () => { - const ruleTester = new RuleTester(); - ruleTester.run('"NOSONAR" comments should not be used', rule, { - valid: [ - { - code: '//', - }, - { - code: '/* */', - }, - { - code: '// foo', - }, - { - code: '/* foo */', - }, - { - code: '// no sonar', - }, - { - code: '/* no sonar */', - }, - ], - invalid: [ - { - code: '// NOSONAR', - errors: [ - { - message: '"NOSONAR" comments should not be used.', - line: 1, - column: 1, - }, - ], - }, - { - code: '// nosonar', - errors: 1, - }, - { - code: '/* NOSONAR */', - errors: 1, - }, - { - code: '/* nosonar */', - errors: 1, - }, - { - code: '// NOSONARSOURCE', - errors: 1, - }, - { - code: '/* NOSONARSOURCE */', - errors: 1, - }, - ], + it('S1291', () => { + const ruleTester = new RuleTester(); + ruleTester.run('"NOSONAR" comments should not be used', rule, { + valid: [ + { + code: '//', + }, + { + code: '/* */', + }, + { + code: '// foo', + }, + { + code: '/* foo */', + }, + { + code: '// no sonar', + }, + { + code: '/* no sonar */', + }, + ], + invalid: [ + { + code: '// NOSONAR', + errors: [ + { + message: '"NOSONAR" comments should not be used.', + line: 1, + column: 1, + }, + ], + }, + { + code: '// nosonar', + errors: 1, + }, + { + code: '/* NOSONAR */', + errors: 1, + }, + { + code: '/* nosonar */', + errors: 1, + }, + { + code: '// NOSONARSOURCE', + errors: 1, + }, + { + code: '/* NOSONARSOURCE */', + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1301/unit.test.ts b/packages/jsts/src/rules/S1301/unit.test.ts index 276838efb4..ed1e98555c 100644 --- a/packages/jsts/src/rules/S1301/unit.test.ts +++ b/packages/jsts/src/rules/S1301/unit.test.ts @@ -16,48 +16,50 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1301', () => { - const ruleTester = new RuleTester(); + it('S1301', () => { + const ruleTester = new RuleTester(); - ruleTester.run('"if" statements should be preferred over "switch" when simpler', rule, { - valid: [ - { code: 'switch (a) { case 1: case 2: break; default: doSomething(); break; }' }, - { code: 'switch (a) { case 1: break; default: doSomething(); break; case 2: }' }, - { code: 'switch (a) { case 1: break; case 2: }' }, - ], - invalid: [ - { - code: 'switch (a) { case 1: doSomething(); break; default: doSomething(); }', - errors: [ - { - messageId: 'replaceSwitch', - column: 1, - endColumn: 7, - }, - ], - }, - { - code: 'switch (a) { case 1: break; }', - errors: [ - { - messageId: 'replaceSwitch', - column: 1, - endColumn: 7, - }, - ], - }, - { - code: 'switch (a) {}', - errors: [ - { - messageId: 'replaceSwitch', - column: 1, - endColumn: 7, - }, - ], - }, - ], + ruleTester.run('"if" statements should be preferred over "switch" when simpler', rule, { + valid: [ + { code: 'switch (a) { case 1: case 2: break; default: doSomething(); break; }' }, + { code: 'switch (a) { case 1: break; default: doSomething(); break; case 2: }' }, + { code: 'switch (a) { case 1: break; case 2: }' }, + ], + invalid: [ + { + code: 'switch (a) { case 1: doSomething(); break; default: doSomething(); }', + errors: [ + { + messageId: 'replaceSwitch', + column: 1, + endColumn: 7, + }, + ], + }, + { + code: 'switch (a) { case 1: break; }', + errors: [ + { + messageId: 'replaceSwitch', + column: 1, + endColumn: 7, + }, + ], + }, + { + code: 'switch (a) {}', + errors: [ + { + messageId: 'replaceSwitch', + column: 1, + endColumn: 7, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S131/unit.test.ts b/packages/jsts/src/rules/S131/unit.test.ts index aa95555596..2f2c2ec7c9 100644 --- a/packages/jsts/src/rules/S131/unit.test.ts +++ b/packages/jsts/src/rules/S131/unit.test.ts @@ -16,24 +16,25 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTester = new RuleTester(); describe('S131', () => { - ruleTester.run('"switch" statements should have "default" clauses', rule, { - valid: [ - { - code: ` + it('S131', () => { + ruleTester.run('"switch" statements should have "default" clauses', rule, { + valid: [ + { + code: ` switch (x) { case 0: break; default: break; }`, - }, - { - code: ` + }, + { + code: ` type T = 'foo' | 'bar'; const x = 'foo' as T; switch (x) { @@ -43,9 +44,9 @@ describe('S131', () => { break; } `, - }, - { - code: ` + }, + { + code: ` enum Direction { Up, Down @@ -61,58 +62,58 @@ describe('S131', () => { break; } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` switch (x) { case 0: break; }`, - errors: [ - { - message: `Add a "default" clause to this "switch" statement.`, - line: 2, - endLine: 2, - column: 9, - endColumn: 15, - suggestions: [ - { - messageId: 'addDefault', - output: ` + errors: [ + { + message: `Add a "default" clause to this "switch" statement.`, + line: 2, + endLine: 2, + column: 9, + endColumn: 15, + suggestions: [ + { + messageId: 'addDefault', + output: ` switch (x) { case 0: break; default: { throw new Error('Not implemented yet'); } }`, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` switch (x) { }`, - errors: [ - { - messageId: 'switchDefault', - line: 2, - suggestions: [ - { - messageId: 'addDefault', - output: ` + errors: [ + { + messageId: 'switchDefault', + line: 2, + suggestions: [ + { + messageId: 'addDefault', + output: ` switch (x) { default: { throw new Error('Not implemented yet'); } }`, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` type T = 'foo' | 'bar'; const x = 'foo' as T; switch (x) { @@ -120,17 +121,17 @@ describe('S131', () => { break; } `, - errors: [ - { - message: `Switch is not exhaustive. Cases not matched: "bar"`, - line: 4, - endLine: 4, - column: 9, - endColumn: 15, - suggestions: [ - { - messageId: 'addMissingCases', - output: ` + errors: [ + { + message: `Switch is not exhaustive. Cases not matched: "bar"`, + line: 4, + endLine: 4, + column: 9, + endColumn: 15, + suggestions: [ + { + messageId: 'addMissingCases', + output: ` type T = 'foo' | 'bar'; const x = 'foo' as T; switch (x) { @@ -139,11 +140,12 @@ describe('S131', () => { case "bar": { throw new Error('Not implemented yet: "bar" case') } } `, - }, - ], - }, - ], - }, - ], + }, + ], + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1313/unit.test.ts b/packages/jsts/src/rules/S1313/unit.test.ts index e43f497a58..74ae6c57e3 100644 --- a/packages/jsts/src/rules/S1313/unit.test.ts +++ b/packages/jsts/src/rules/S1313/unit.test.ts @@ -16,15 +16,16 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1313', () => { - const ruleTesterTs = new RuleTester(); + it('S1313', () => { + const ruleTesterTs = new RuleTester(); - ruleTesterTs.run('Hardcoded ip addresses should be avoided', rule, { - valid: [ - { - code: ` + ruleTesterTs.run('Hardcoded ip addresses should be avoided', rule, { + valid: [ + { + code: ` address = "127.0.0.0"; address = "::ffff:0:127.0.0.0"; address = "127.0.255.0"; @@ -48,41 +49,42 @@ describe('S1313', () => { address = "::ffff:0:198.51.100.5", address = "203.0.113.5", address = "2001:db8:acad:1::ff"`, - }, - ], - invalid: [ - { - code: `address = "192.168.12.42";`, - errors: [ - { - message: 'Make sure using a hardcoded IP address 192.168.12.42 is safe here.', - line: 1, - column: 11, - endLine: 1, - endColumn: 26, - }, - ], - }, - { - code: `address = "2001:0db8:3c4d:0015:0000:0000:1a2f:1a2b";`, - errors: 1, - }, - { - code: `address = "0012.0012.0012.0001";`, - errors: 1, - }, - { - code: `address = "0xa.0xa.0xa.0x1";`, - errors: 1, - }, - { - code: `address = "10.10.10.1/32";`, - errors: 1, - }, - { - code: `address = "::ffff:0:10.10.10.1";`, - errors: 1, - }, - ], + }, + ], + invalid: [ + { + code: `address = "192.168.12.42";`, + errors: [ + { + message: 'Make sure using a hardcoded IP address 192.168.12.42 is safe here.', + line: 1, + column: 11, + endLine: 1, + endColumn: 26, + }, + ], + }, + { + code: `address = "2001:0db8:3c4d:0015:0000:0000:1a2f:1a2b";`, + errors: 1, + }, + { + code: `address = "0012.0012.0012.0001";`, + errors: 1, + }, + { + code: `address = "0xa.0xa.0xa.0x1";`, + errors: 1, + }, + { + code: `address = "10.10.10.1/32";`, + errors: 1, + }, + { + code: `address = "::ffff:0:10.10.10.1";`, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S134/unit.test.ts b/packages/jsts/src/rules/S134/unit.test.ts index 3b6db83349..d67e39e829 100644 --- a/packages/jsts/src/rules/S134/unit.test.ts +++ b/packages/jsts/src/rules/S134/unit.test.ts @@ -17,7 +17,7 @@ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; import { EncodedMessage, IssueLocation } from '../helpers/index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTester = new RuleTester(); @@ -28,13 +28,14 @@ const createOptions = (maximumNestingLevel: number) => { }; describe('S134', () => { - ruleTester.run( - 'Refactor this code to not nest more than X if/for/while/switch/try statements.', - rule, - { - valid: [ - { - code: ` + it('S134', () => { + ruleTester.run( + 'Refactor this code to not nest more than X if/for/while/switch/try statements.', + rule, + { + valid: [ + { + code: ` if (true) { if (true) { for (const i of arr) { @@ -42,10 +43,10 @@ describe('S134', () => { } } `, - options: createOptions(THRESHOLD), - }, - { - code: ` + options: createOptions(THRESHOLD), + }, + { + code: ` if (true) { if (true) { for (const i of arr) { @@ -55,10 +56,10 @@ describe('S134', () => { } } `, - options: createOptions(4), - }, - { - code: ` + options: createOptions(4), + }, + { + code: ` if (true) { } else if (false) { while (true) { @@ -67,12 +68,12 @@ describe('S134', () => { } } `, - options: createOptions(THRESHOLD), - }, - ], - invalid: [ - invalid( - ` + options: createOptions(THRESHOLD), + }, + ], + invalid: [ + invalid( + ` if (true) { // ^^ if (true) { @@ -82,10 +83,10 @@ describe('S134', () => { } } }`, - 2, - ), - invalid( - ` + 2, + ), + invalid( + ` if (true) { } else if (true) { @@ -97,10 +98,10 @@ describe('S134', () => { } } }`, - 2, - ), - invalid( - ` + 2, + ), + invalid( + ` for (var i = 0; i < 0; i++) { // level 1 // ^^^ for (bar in MyArray) { // level 2 @@ -108,66 +109,67 @@ describe('S134', () => { while (false) { // level 3 //----------^^^^^--- }}}`, - 2, - ), - ], - }, - ); -}); + 2, + ), + ], + }, + ); + }); -function invalid(code: string, threshold = THRESHOLD) { - let primaryLocation: IssueLocation; - const secondaryLocations: IssueLocation[] = []; - const lines = code.split('\n'); - for (const [index, line] of lines.entries()) { - let found: RegExpMatchArray | null; + function invalid(code: string, threshold = THRESHOLD) { + let primaryLocation: IssueLocation; + const secondaryLocations: IssueLocation[] = []; + const lines = code.split('\n'); + for (const [index, line] of lines.entries()) { + let found: RegExpMatchArray | null; - const primary = /\/\/\s*\-+(\^+)\-+/; - found = line.match(primary); - if (found) { - const marker = found[1]; - const column = line.indexOf(marker) + 1; // Column is one-based in tests - const msg = `Refactor this code to not nest more than ${threshold} if/for/while/switch/try statements.`; - primaryLocation = location(index, column, index, column + marker.length, msg); - } + const primary = /\/\/\s*\-+(\^+)\-+/; + found = line.match(primary); + if (found) { + const marker = found[1]; + const column = line.indexOf(marker) + 1; // Column is one-based in tests + const msg = `Refactor this code to not nest more than ${threshold} if/for/while/switch/try statements.`; + primaryLocation = location(index, column, index, column + marker.length, msg); + } - const secondary = /\/\/\s*(\^+)/; - found = line.match(secondary); - if (found) { - const marker = found[1]; - const column = line.indexOf(marker); - secondaryLocations.push(location(index, column, index, column + marker.length, '+1')); + const secondary = /\/\/\s*(\^+)/; + found = line.match(secondary); + if (found) { + const marker = found[1]; + const column = line.indexOf(marker); + secondaryLocations.push(location(index, column, index, column + marker.length, '+1')); + } } - } - return { - code, - errors: [error(primaryLocation, secondaryLocations)], - options: createOptions(threshold), - }; -} + return { + code, + errors: [error(primaryLocation, secondaryLocations)], + options: createOptions(threshold), + }; + } -function error(primaryLocation: IssueLocation, secondaryLocations: IssueLocation[]) { - return { - ...primaryLocation, - message: encode(primaryLocation.message, secondaryLocations), - }; -} + function error(primaryLocation: IssueLocation, secondaryLocations: IssueLocation[]) { + return { + ...primaryLocation, + message: encode(primaryLocation.message, secondaryLocations), + }; + } -function encode(message: string, secondaryLocations: IssueLocation[]): string { - const encodedMessage: EncodedMessage = { - message, - secondaryLocations, - }; - return JSON.stringify(encodedMessage); -} + function encode(message: string, secondaryLocations: IssueLocation[]): string { + const encodedMessage: EncodedMessage = { + message, + secondaryLocations, + }; + return JSON.stringify(encodedMessage); + } -function location( - line: number, - column: number, - endLine: number, - endColumn: number, - message: string, -): IssueLocation { - return { message, column, line, endColumn, endLine }; -} + function location( + line: number, + column: number, + endLine: number, + endColumn: number, + message: string, + ): IssueLocation { + return { message, column, line, endColumn, endLine }; + } +}); diff --git a/packages/jsts/src/rules/S135/unit.test.ts b/packages/jsts/src/rules/S135/unit.test.ts index 506770a007..da94c5467b 100644 --- a/packages/jsts/src/rules/S135/unit.test.ts +++ b/packages/jsts/src/rules/S135/unit.test.ts @@ -16,7 +16,7 @@ */ import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTesterJs = new DefaultParserRuleTester(); const ruleTesterTs = new RuleTester(); @@ -216,14 +216,16 @@ const testCases = { }; describe('S135', () => { - ruleTesterJs.run( - 'Loops should not contain more than a single "break" or "continue" statement JS', - rule, - testCases, - ); - ruleTesterTs.run( - 'Loops should not contain more than a single "break" or "continue" statement TS', - rule, - testCases, - ); + it('S135', () => { + ruleTesterJs.run( + 'Loops should not contain more than a single "break" or "continue" statement JS', + rule, + testCases, + ); + ruleTesterTs.run( + 'Loops should not contain more than a single "break" or "continue" statement TS', + rule, + testCases, + ); + }); }); diff --git a/packages/jsts/src/rules/S138/unit.test.ts b/packages/jsts/src/rules/S138/unit.test.ts index f199ec5e3a..090792de51 100644 --- a/packages/jsts/src/rules/S138/unit.test.ts +++ b/packages/jsts/src/rules/S138/unit.test.ts @@ -16,30 +16,31 @@ */ import { rule } from './index.js'; import { DefaultParserRuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTester = new DefaultParserRuleTester(); describe('S138', () => { - ruleTester.run('Too many lines in functions', rule, { - valid: [ - { - code: `function f() { + it('S138', () => { + ruleTester.run('Too many lines in functions', rule, { + valid: [ + { + code: `function f() { console.log("a"); }`, - options: [{ maximum: 3 }], - }, - { - code: `function f() { + options: [{ maximum: 3 }], + }, + { + code: `function f() { console.log("a"); }`, - options: [{ maximum: 3 }], - }, - { - code: `function f() { + options: [{ maximum: 3 }], + }, + { + code: `function f() { // comment console.log("a"); /* @@ -48,110 +49,110 @@ describe('S138', () => { comment */ }`, - options: [{ maximum: 3 }], - }, - { - code: `function foo() { + options: [{ maximum: 3 }], + }, + { + code: `function foo() { console.log("a"); // End of line comment }`, - options: [{ maximum: 3 }], - }, - { - code: ` + options: [{ maximum: 3 }], + }, + { + code: ` console.log("a"); function foo() { console.log("a"); } console.log("a"); `, - options: [{ maximum: 3 }], - }, - { - code: `function f() { + options: [{ maximum: 3 }], + }, + { + code: `function f() { function g() { console.log("a"); } }`, - options: [{ maximum: 5 }], - }, - { - code: `( + options: [{ maximum: 5 }], + }, + { + code: `( function () { } ) ()`, //IIFE are ignored - options: [{ maximum: 6 }], - }, - { - // React Function Component - code: ` + options: [{ maximum: 6 }], + }, + { + // React Function Component + code: ` function Welcome() { const greeting = 'Hello, world!'; return

{greeting}

}`, - options: [{ maximum: 2 }], - }, - { - // React Function Component using function expressions and JSXFragments - code: ` + options: [{ maximum: 2 }], + }, + { + // React Function Component using function expressions and JSXFragments + code: ` let a = function Welcome() { const greeting = 'Hello, world!'; return <>

{greeting}

}`, - options: [{ maximum: 2 }], - }, - { - // React Function Component - using arrow function - code: ` + options: [{ maximum: 2 }], + }, + { + // React Function Component - using arrow function + code: ` const Welcome = () => { const greeting = 'Hello, world!'; return

{greeting}

}`, - options: [{ maximum: 2 }], - }, - ], - invalid: [ - { - code: `function foo() { + options: [{ maximum: 2 }], + }, + ], + invalid: [ + { + code: `function foo() { console.log("a"); console.log("a"); }`, - options: [{ maximum: 3 }], - errors: [ - { - message: `This function has 4 lines, which is greater than the 3 lines authorized. Split it into smaller functions.`, - line: 1, - endLine: 1, - column: 10, - endColumn: 13, - }, - ], - }, - { - code: `function foo() { + options: [{ maximum: 3 }], + errors: [ + { + message: `This function has 4 lines, which is greater than the 3 lines authorized. Split it into smaller functions.`, + line: 1, + endLine: 1, + column: 10, + endColumn: 13, + }, + ], + }, + { + code: `function foo() { console.log("a"); console.log("a"); console.log("b"); }`, - options: [{ maximum: 4 }], - errors: [ - { - message: `This function has 5 lines, which is greater than the 4 lines authorized. Split it into smaller functions.`, - line: 1, - endLine: 1, - column: 10, - endColumn: 13, - }, - ], - }, - { - // React Function Component - code: ` + options: [{ maximum: 4 }], + errors: [ + { + message: `This function has 5 lines, which is greater than the 4 lines authorized. Split it into smaller functions.`, + line: 1, + endLine: 1, + column: 10, + endColumn: 13, + }, + ], + }, + { + // React Function Component + code: ` function Welcome() { const greeting = 'Hello, world!'; @@ -163,9 +164,10 @@ function return

{greeting}

}`, - options: [{ maximum: 2 }], - errors: 1, - }, - ], + options: [{ maximum: 2 }], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1439/unit.test.ts b/packages/jsts/src/rules/S1439/unit.test.ts index a462383106..00140ffb12 100644 --- a/packages/jsts/src/rules/S1439/unit.test.ts +++ b/packages/jsts/src/rules/S1439/unit.test.ts @@ -16,55 +16,57 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1439', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Only "while", "do", "for" and "switch" statements should be labelled', rule, { - valid: [ - { - code: ` + it('S1439', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Only "while", "do", "for" and "switch" statements should be labelled', rule, { + valid: [ + { + code: ` loop1: for (var i = 0; i < 5; i++) { continue loop1; }`, - }, - { - code: `loop1: for (index in myArray) {}`, - }, - { - code: `loop1: for (val of myArray) {}`, - }, - { - code: `loop1: while (i < 10) {}`, - }, - { - code: `loop1: do {} while (i < 10)`, - }, - { - code: `mySwitch: switch(x) { default: break mySwitch; }`, - }, - ], - invalid: [ - { - code: ` + }, + { + code: `loop1: for (index in myArray) {}`, + }, + { + code: `loop1: for (val of myArray) {}`, + }, + { + code: `loop1: while (i < 10) {}`, + }, + { + code: `loop1: do {} while (i < 10)`, + }, + { + code: `mySwitch: switch(x) { default: break mySwitch; }`, + }, + ], + invalid: [ + { + code: ` invalidLabel: //^^^^^^^^^^^^ if (myBool) {}`, - errors: [ - { - message: 'Remove this "invalidLabel" label.', - line: 2, - endLine: 2, - column: 9, - endColumn: 21, - }, - ], - }, - { - code: `invalidLabel: var x = 0;`, - errors: 1, - }, - ], + errors: [ + { + message: 'Remove this "invalidLabel" label.', + line: 2, + endLine: 2, + column: 9, + endColumn: 21, + }, + ], + }, + { + code: `invalidLabel: var x = 0;`, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1451/unit.test.ts b/packages/jsts/src/rules/S1451/unit.test.ts index cffa41b57b..f3db989ffa 100644 --- a/packages/jsts/src/rules/S1451/unit.test.ts +++ b/packages/jsts/src/rules/S1451/unit.test.ts @@ -16,88 +16,90 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1451', () => { - const ruleTester = new RuleTester(); + it('S1451', () => { + const ruleTester = new RuleTester(); - const errors = [ - { - message: 'Add or update the header of this file.', - line: 0, - column: 1, - }, - ]; + const errors = [ + { + message: 'Add or update the header of this file.', + line: 0, + column: 1, + }, + ]; - const file1 = `// copyright 2005 + const file1 = `// copyright 2005 function file1() { } `; - const file2 = `// copyright 2012 + const file2 = `// copyright 2012 // foo function file2() { } `; - const file3 = `/*foo http://www.example.org*/ + const file3 = `/*foo http://www.example.org*/ function file3() { } `; - ruleTester.run('File header', rule, { - valid: [ - valid(`foo();`, '', true), + ruleTester.run('File header', rule, { + valid: [ + valid(`foo();`, '', true), - valid(file1, '// copyright 2005', false), - valid(file2, '// copyright 2012', false), - valid(file2, '// copyright 2012\n// foo', false), - valid(file2, '// copyright 2012\r\n// foo', false), - valid(file3, '/*foo http://www.example.org*/', false), + valid(file1, '// copyright 2005', false), + valid(file2, '// copyright 2012', false), + valid(file2, '// copyright 2012\n// foo', false), + valid(file2, '// copyright 2012\r\n// foo', false), + valid(file3, '/*foo http://www.example.org*/', false), - valid(file1, '// copyright 2005', true), - valid(file1, '// copyright 20\\d\\d', true), - valid(file2, '// copyright 20\\d\\d', true), - valid(file2, '// copyright 20\\d\\d\\n// foo', true), - valid(file2, '// copyright 20\\d{2}\\r?\\n// foo', true), + valid(file1, '// copyright 2005', true), + valid(file1, '// copyright 20\\d\\d', true), + valid(file2, '// copyright 20\\d\\d', true), + valid(file2, '// copyright 20\\d\\d\\n// foo', true), + valid(file2, '// copyright 20\\d{2}\\r?\\n// foo', true), - // invalid regexp, should log error - valid('whatever', '*', true), - ], - invalid: [ - invalid(`foo();`, '// companyName', false), - invalid(file1, '// copyright 20\\d\\d', false), - invalid(file2, '// copyright 2005', false), - invalid(file2, '// copyright 2012\r\r// foo', false), - invalid(file2, '// copyright 2012\n// foo\n\n\n\n\n\n\n\n\n\ngfoo', false), - - invalid(file2, '// copyright 20\\d{3}\\n// foo', true), - invalid(file2, '// copyright 20\\d\\d\\r// foo', true), - ], - }); - - function valid(code: string, headerFormat: string, isRegularExpression: boolean) { - return { - code, - options: [ - { - headerFormat, - isRegularExpression, - }, + // invalid regexp, should log error + valid('whatever', '*', true), ], - }; - } + invalid: [ + invalid(`foo();`, '// companyName', false), + invalid(file1, '// copyright 20\\d\\d', false), + invalid(file2, '// copyright 2005', false), + invalid(file2, '// copyright 2012\r\r// foo', false), + invalid(file2, '// copyright 2012\n// foo\n\n\n\n\n\n\n\n\n\ngfoo', false), - function invalid(code: string, headerFormat: string, isRegularExpression: boolean = false) { - return { - code, - options: [ - { - headerFormat, - isRegularExpression, - }, + invalid(file2, '// copyright 20\\d{3}\\n// foo', true), + invalid(file2, '// copyright 20\\d\\d\\r// foo', true), ], - errors, - }; - } + }); + + function valid(code: string, headerFormat: string, isRegularExpression: boolean) { + return { + code, + options: [ + { + headerFormat, + isRegularExpression, + }, + ], + }; + } + + function invalid(code: string, headerFormat: string, isRegularExpression: boolean = false) { + return { + code, + options: [ + { + headerFormat, + isRegularExpression, + }, + ], + errors, + }; + } + }); }); diff --git a/packages/jsts/src/rules/S1472/unit.test.ts b/packages/jsts/src/rules/S1472/unit.test.ts index 9482a9162a..9b3e2bf9c0 100644 --- a/packages/jsts/src/rules/S1472/unit.test.ts +++ b/packages/jsts/src/rules/S1472/unit.test.ts @@ -16,177 +16,179 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1472', () => { - const ruleTester = new RuleTester(); - ruleTester.run(`Function call arguments should not start on new lines`, rule, { - valid: [ - { - code: ` + it('S1472', () => { + const ruleTester = new RuleTester(); + ruleTester.run(`Function call arguments should not start on new lines`, rule, { + valid: [ + { + code: ` foo(bar); `, - }, - { - code: ` + }, + { + code: ` foo(bar)(baz)(qux); `, - }, - { - code: ` + }, + { + code: ` foo(bar) (baz) (qux); `, - }, - { - code: ` + }, + { + code: ` foo (bar, baz, qux); `, - }, - { - code: ` + }, + { + code: ` (foo )((bar)); `, - }, - { - code: ` + }, + { + code: ` const MyContext = React.createContext<{ foo: number, bar: number, }>({ foo: 1, bar: 2 }); `, - }, - { - code: ` + }, + { + code: ` const MyContext = React.createContext ('foo'); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` foo (bar);`, - errors: [ - { - message: `Make those call arguments start on line 2.`, - line: 3, - endLine: 3, - column: 9, - endColumn: 14, - }, - ], - }, - { - code: `(function iieflike(factory){} + errors: [ + { + message: `Make those call arguments start on line 2.`, + line: 3, + endLine: 3, + column: 9, + endColumn: 14, + }, + ], + }, + { + code: `(function iieflike(factory){} (function () { //A lot of code... } ))`, - errors: [ - { - message: `Make those call arguments start on line 1.`, - line: 2, - column: 7, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Make those call arguments start on line 1.`, + line: 2, + column: 7, + }, + ], + }, + { + code: ` foo(bar)[baz] (qux); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` var a = b (x || y).doSomething() `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` var a = (a || b) (x || y).doSomething() `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` var a = (a || b) (x).doSomething() `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` var a = b (x || y).doSomething() `, - errors: 1, - }, - { - code: 'let x = function() {}\n `hello`', - errors: [ - { - message: `Make this template literal start on line 1.`, - line: 2, - endLine: 2, - column: 2, - endColumn: 3, - }, - ], - }, - { - code: 'let x = function() {}\nx\n`hello`', - errors: [ - { - message: `Make this template literal start on line 2.`, - line: 3, - endLine: 3, - column: 1, - endColumn: 2, - }, - ], - }, - { - code: ` + errors: 1, + }, + { + code: 'let x = function() {}\n `hello`', + errors: [ + { + message: `Make this template literal start on line 1.`, + line: 2, + endLine: 2, + column: 2, + endColumn: 3, + }, + ], + }, + { + code: 'let x = function() {}\nx\n`hello`', + errors: [ + { + message: `Make this template literal start on line 2.`, + line: 3, + endLine: 3, + column: 1, + endColumn: 2, + }, + ], + }, + { + code: ` const MyContext = React.createContext<{ foo: number, bar: number, }> ({ foo: 1, bar: 2 }); `, - errors: [ - { - message: 'Make those call arguments start on line 5.', - line: 6, - endLine: 6, - column: 7, - endColumn: 27, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Make those call arguments start on line 5.', + line: 6, + endLine: 6, + column: 7, + endColumn: 27, + }, + ], + }, + { + code: ` const MyContext = React.createContext ('foo'); `, - errors: [ - { - message: 'Make those call arguments start on line 2.', - line: 3, - endLine: 3, - column: 7, - endColumn: 14, - }, - ], - }, - ], + errors: [ + { + message: 'Make those call arguments start on line 2.', + line: 3, + endLine: 3, + column: 7, + endColumn: 14, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1479/unit.test.ts b/packages/jsts/src/rules/S1479/unit.test.ts index 0ad4be44ce..3bd13edd81 100644 --- a/packages/jsts/src/rules/S1479/unit.test.ts +++ b/packages/jsts/src/rules/S1479/unit.test.ts @@ -16,24 +16,25 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1479', () => { - const ruleTester = new RuleTester(); + it('S1479', () => { + const ruleTester = new RuleTester(); - ruleTester.run('max-switch-cases', rule, { - valid: [ - { - code: `switch(i) { + ruleTester.run('max-switch-cases', rule, { + valid: [ + { + code: `switch(i) { case 1: f(); case 2: g(); }`, - }, - // default branch is excluded - { - code: `switch(i) { + }, + // default branch is excluded + { + code: `switch(i) { case 1: f(); case 2: @@ -41,47 +42,48 @@ describe('S1479', () => { default: console.log("foo"); }`, - options: [2], - }, - // empty branches are not counted - { - code: `switch(i) { + options: [2], + }, + // empty branches are not counted + { + code: `switch(i) { case 1: case 2: g(); case 3: console.log("foo"); }`, - options: [2], - }, - // empty switch statement - { - code: `switch(i) {}`, - }, - ], - invalid: [ - { - code: `switch(i) { + options: [2], + }, + // empty switch statement + { + code: `switch(i) {}`, + }, + ], + invalid: [ + { + code: `switch(i) { case 1: f(); case 2: g(); }`, - options: [1], - errors: [ - { - messageId: 'reduceNumberOfNonEmptySwitchCases', - data: { - numSwitchCases: 2, - maxSwitchCases: 1, + options: [1], + errors: [ + { + messageId: 'reduceNumberOfNonEmptySwitchCases', + data: { + numSwitchCases: 2, + maxSwitchCases: 1, + }, + line: 1, + endLine: 1, + column: 1, + endColumn: 7, }, - line: 1, - endLine: 1, - column: 1, - endColumn: 7, - }, - ], - }, - ], + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1481/unit.test.ts b/packages/jsts/src/rules/S1481/unit.test.ts index 4db248f675..5ee6c3a2d3 100644 --- a/packages/jsts/src/rules/S1481/unit.test.ts +++ b/packages/jsts/src/rules/S1481/unit.test.ts @@ -16,15 +16,16 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1481', () => { - const ruleTester = new RuleTester(); + it('S1481', () => { + const ruleTester = new RuleTester(); - ruleTester.run('Local variables should be used', rule, { - valid: [ - { - code: ` + ruleTester.run('Local variables should be used', rule, { + valid: [ + { + code: ` var a = 0; // OK, global export let b = 0 // OK, global @@ -60,28 +61,28 @@ describe('S1481', () => { return new RegExp(\`\${foo}\`); } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function fun() { var a = 0; // Noncompliant var b = 1; // OK return b; }`, - errors: [ - { - message: `Remove the declaration of the unused 'a' variable.`, - line: 3, - endLine: 3, - column: 13, - endColumn: 14, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Remove the declaration of the unused 'a' variable.`, + line: 3, + endLine: 3, + column: 13, + endColumn: 14, + }, + ], + }, + { + code: ` function fun1() { var a = 0; // OK function nested() { // Noncompliant @@ -108,35 +109,35 @@ describe('S1481', () => { var b = 1; // OK return b; }`, - errors: [ - { - message: `Remove unused function 'nested'.`, - line: 4, - }, - { - messageId: 'unusedVariable', - line: 10, - }, - { - messageId: 'unusedFunction', - line: 11, - }, - { - messageId: 'unusedVariable', - line: 17, - }, - { - messageId: 'unusedVariable', - line: 18, - }, - { - messageId: 'unusedVariable', - line: 24, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Remove unused function 'nested'.`, + line: 4, + }, + { + messageId: 'unusedVariable', + line: 10, + }, + { + messageId: 'unusedFunction', + line: 11, + }, + { + messageId: 'unusedVariable', + line: 17, + }, + { + messageId: 'unusedVariable', + line: 18, + }, + { + messageId: 'unusedVariable', + line: 24, + }, + ], + }, + { + code: ` function fun1() { var f1 = function() { console.log("f1"); } // Noncompliant } @@ -167,43 +168,43 @@ describe('S1481', () => { class A {} // OK, ignore anything except variables and functions } `, - errors: [ - { - messageId: 'unusedVariable', - line: 3, - }, - { - messageId: 'unusedFunction', - line: 7, - }, - { - messageId: 'unusedVariable', - line: 12, - }, - { - messageId: 'unusedVariable', - line: 17, - }, - { - messageId: 'unusedVariable', - line: 18, - }, - { - messageId: 'unusedVariable', - line: 22, - }, - { - messageId: 'unusedVariable', - line: 26, - }, - { - messageId: 'unusedVariable', - line: 27, - }, - ], - }, - { - code: ` + errors: [ + { + messageId: 'unusedVariable', + line: 3, + }, + { + messageId: 'unusedFunction', + line: 7, + }, + { + messageId: 'unusedVariable', + line: 12, + }, + { + messageId: 'unusedVariable', + line: 17, + }, + { + messageId: 'unusedVariable', + line: 18, + }, + { + messageId: 'unusedVariable', + line: 22, + }, + { + messageId: 'unusedVariable', + line: 26, + }, + { + messageId: 'unusedVariable', + line: 27, + }, + ], + }, + { + code: ` function objectDestructuringException(obj) { var {a, b, c, ...interestingProps} = obj; // OK foo(interestingProps); @@ -221,26 +222,26 @@ describe('S1481', () => { var {} = obj; }`, - errors: [ - { - message: `Remove the declaration of the unused 'b1' variable.`, - line: 6, - column: 18, - }, - { - message: `Remove the declaration of the unused 'interestingProps2' variable.`, - line: 10, - column: 29, - }, - { - message: `Remove the declaration of the unused 'b3' variable.`, - line: 13, - column: 21, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Remove the declaration of the unused 'b1' variable.`, + line: 6, + column: 18, + }, + { + message: `Remove the declaration of the unused 'interestingProps2' variable.`, + line: 10, + column: 29, + }, + { + message: `Remove the declaration of the unused 'b3' variable.`, + line: 13, + column: 21, + }, + ], + }, + { + code: ` const constUsed = "this is used"; let letUsed = "this is used"; var varUsed = "this is used"; @@ -253,14 +254,14 @@ describe('S1481', () => { } }`, - errors: [ - { messageId: 'unusedVariable', line: 6 }, - { messageId: 'unusedVariable', line: 7 }, - { messageId: 'unusedFunction', line: 10 }, - ], - }, - { - code: ` + errors: [ + { messageId: 'unusedVariable', line: 6 }, + { messageId: 'unusedVariable', line: 7 }, + { messageId: 'unusedFunction', line: 10 }, + ], + }, + { + code: ` function used_in_jsx(icon) { const UsedIcon = icon; const UnusedIcon = icon; // Noncompliant @@ -274,10 +275,11 @@ describe('S1481', () => { return {tagContent}; } `, - errors: [ - { line: 4, message: `Remove the declaration of the unused \'UnusedIcon\' variable.` }, - ], - }, - ], + errors: [ + { line: 4, message: `Remove the declaration of the unused \'UnusedIcon\' variable.` }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1488/unit.test.ts b/packages/jsts/src/rules/S1488/unit.test.ts index 61b1585094..f74e0460f2 100644 --- a/packages/jsts/src/rules/S1488/unit.test.ts +++ b/packages/jsts/src/rules/S1488/unit.test.ts @@ -16,143 +16,144 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1488', () => { - const ruleTester = new RuleTester(); + it('S1488', () => { + const ruleTester = new RuleTester(); - ruleTester.run('prefer-immediate-return', rule, { - valid: [ - { - code: ` + ruleTester.run('prefer-immediate-return', rule, { + valid: [ + { + code: ` function thrown_ok() { throw new Error(); } `, - }, - { - code: ` + }, + { + code: ` function thrown_expression() { const x = new Error(); throw foo(x); } `, - }, - { - code: ` + }, + { + code: ` function thrown_different_variable(y) { const x = new Error(); throw y; } `, - }, - { - code: ` + }, + { + code: ` function code_between_declaration_and_return() { let x = 42; foo(); return x; } `, - }, - { - code: ` + }, + { + code: ` function return_expression() { let x = 42; return x + 5; } `, - }, - { - code: ` + }, + { + code: ` function return_without_value() { let x = 42; return; } `, - }, - { - code: ` + }, + { + code: ` function not_return_statement() { let x = 42; foo(x); } `, - }, - { - code: ` + }, + { + code: ` function no_init_value() { let x; return x; } `, - }, - { - code: ` + }, + { + code: ` function pattern_declared() { let { x } = foo(); return x; } `, - }, - { - code: ` + }, + { + code: ` function two_variables_declared() { let x = 42, y; return x; } `, - }, - { - code: ` + }, + { + code: ` function different_variable_returned(y) { let x = 42; return y; } `, - }, - { - code: ` + }, + { + code: ` function only_return() { return 42; } `, - }, - { - code: ` + }, + { + code: ` function one_statement() { foo(); } `, - }, - { - code: ` + }, + { + code: ` function empty_block() {} `, - }, - { - code: ` + }, + { + code: ` let arrow_function_ok = (a, b) => { return a + b; }; `, - }, - { - code: ` + }, + { + code: ` let arrow_function_no_block = (a, b) => a + b; `, - }, - { - code: ` + }, + { + code: ` function variable_has_type_annotation() { let foo: number = 1; return foo; } `, - }, - { - code: ` + }, + { + code: ` function variable_is_used() { var bar = { doSomethingElse(p) {}, @@ -163,134 +164,134 @@ describe('S1488', () => { return bar; } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function var_returned() { var x = 42; return x; }`, - errors: [ - { - messageId: 'doImmediateAction', - data: { - action: 'return', - variable: 'x', + errors: [ + { + messageId: 'doImmediateAction', + data: { + action: 'return', + variable: 'x', + }, + line: 3, + column: 19, + endColumn: 21, }, - line: 3, - column: 19, - endColumn: 21, - }, - ], - output: ` + ], + output: ` function var_returned() { return 42; }`, - }, - { - code: ` + }, + { + code: ` function let_returned() { let x = 42; return x; } `, - errors: [ - { - messageId: 'doImmediateAction', - data: { - action: 'return', - variable: 'x', + errors: [ + { + messageId: 'doImmediateAction', + data: { + action: 'return', + variable: 'x', + }, + line: 3, + column: 19, + endColumn: 21, }, - line: 3, - column: 19, - endColumn: 21, - }, - ], - output: ` + ], + output: ` function let_returned() { return 42; } `, - }, - { - code: ` + }, + { + code: ` function const_returned() { const x = 42; return x; } `, - errors: [ - { - messageId: 'doImmediateAction', - data: { - action: 'return', - variable: 'x', + errors: [ + { + messageId: 'doImmediateAction', + data: { + action: 'return', + variable: 'x', + }, + line: 3, + column: 21, + endColumn: 23, }, - line: 3, - column: 21, - endColumn: 23, - }, - ], - output: ` + ], + output: ` function const_returned() { return 42; } `, - }, - { - code: ` + }, + { + code: ` function code_before_declaration() { foo(); var x = 42; return x; } `, - errors: [ - { - messageId: 'doImmediateAction', - data: { - action: 'return', - variable: 'x', + errors: [ + { + messageId: 'doImmediateAction', + data: { + action: 'return', + variable: 'x', + }, + line: 4, + column: 19, + endColumn: 21, }, - line: 4, - column: 19, - endColumn: 21, - }, - ], - output: ` + ], + output: ` function code_before_declaration() { foo(); return 42; } `, - }, - { - code: ` + }, + { + code: ` function thrown_nok() { const x = new Error(); throw x; }`, - errors: [ - { - messageId: 'doImmediateAction', - data: { - action: 'throw', - variable: 'x', + errors: [ + { + messageId: 'doImmediateAction', + data: { + action: 'throw', + variable: 'x', + }, + line: 3, + column: 21, + endColumn: 32, }, - line: 3, - column: 21, - endColumn: 32, - }, - ], - output: ` + ], + output: ` function thrown_nok() { throw new Error(); }`, - }, - { - code: ` + }, + { + code: ` function different_blocks() { if (foo) { let x = foo(); @@ -309,49 +310,49 @@ describe('S1488', () => { } } `, - errors: [ - { - messageId: 'doImmediateAction', - data: { - action: 'return', - variable: 'x', + errors: [ + { + messageId: 'doImmediateAction', + data: { + action: 'return', + variable: 'x', + }, + line: 4, + column: 21, + endColumn: 26, }, - line: 4, - column: 21, - endColumn: 26, - }, - { - messageId: 'doImmediateAction', - data: { - action: 'return', - variable: 'x', + { + messageId: 'doImmediateAction', + data: { + action: 'return', + variable: 'x', + }, + line: 9, + column: 21, + endColumn: 26, }, - line: 9, - column: 21, - endColumn: 26, - }, - { - messageId: 'doImmediateAction', - data: { - action: 'return', - variable: 'x', + { + messageId: 'doImmediateAction', + data: { + action: 'return', + variable: 'x', + }, + line: 12, + column: 21, + endColumn: 26, }, - line: 12, - column: 21, - endColumn: 26, - }, - { - messageId: 'doImmediateAction', - data: { - action: 'return', - variable: 'x', + { + messageId: 'doImmediateAction', + data: { + action: 'return', + variable: 'x', + }, + line: 15, + column: 21, + endColumn: 26, }, - line: 15, - column: 21, - endColumn: 26, - }, - ], - output: ` + ], + output: ` function different_blocks() { if (foo) { return foo(); @@ -366,9 +367,9 @@ describe('S1488', () => { } } `, - }, - { - code: ` + }, + { + code: ` function two_declarations(a) { if (a) { let x = foo(); @@ -379,19 +380,19 @@ describe('S1488', () => { } } `, - errors: [ - { - messageId: 'doImmediateAction', - data: { - action: 'return', - variable: 'x', + errors: [ + { + messageId: 'doImmediateAction', + data: { + action: 'return', + variable: 'x', + }, + line: 4, + column: 21, + endColumn: 26, }, - line: 4, - column: 21, - endColumn: 26, - }, - ], - output: ` + ], + output: ` function two_declarations(a) { if (a) { return foo(); @@ -401,9 +402,9 @@ describe('S1488', () => { } } `, - }, - { - code: ` + }, + { + code: ` function homonymous_is_used() { const bar = { doSomethingElse(p) { @@ -417,20 +418,20 @@ describe('S1488', () => { return bar; } `, - errors: [ - { - messageId: 'doImmediateAction', - data: { - action: 'return', - variable: 'bar', + errors: [ + { + messageId: 'doImmediateAction', + data: { + action: 'return', + variable: 'bar', + }, + line: 3, + column: 23, + endLine: 11, + endColumn: 12, }, - line: 3, - column: 23, - endLine: 11, - endColumn: 12, - }, - ], - output: ` + ], + output: ` function homonymous_is_used() { return { doSomethingElse(p) { @@ -443,9 +444,9 @@ describe('S1488', () => { }; } `, - }, - { - code: ` + }, + { + code: ` function inside_switch(x) { switch (x) { case 1: @@ -457,29 +458,29 @@ describe('S1488', () => { } } `, - errors: [ - { - messageId: 'doImmediateAction', - data: { - action: 'return', - variable: 'y', + errors: [ + { + messageId: 'doImmediateAction', + data: { + action: 'return', + variable: 'y', + }, + line: 5, + column: 25, + endColumn: 26, }, - line: 5, - column: 25, - endColumn: 26, - }, - { - messageId: 'doImmediateAction', - data: { - action: 'return', - variable: 'z', + { + messageId: 'doImmediateAction', + data: { + action: 'return', + variable: 'z', + }, + line: 8, + column: 25, + endColumn: 26, }, - line: 8, - column: 25, - endColumn: 26, - }, - ], - output: ` + ], + output: ` function inside_switch(x) { switch (x) { case 1: @@ -489,33 +490,33 @@ describe('S1488', () => { } } `, - }, - { - code: ` + }, + { + code: ` function var_returned() { var x = 42; return x }`, - errors: [ - { - messageId: 'doImmediateAction', - data: { - action: 'return', - variable: 'x', + errors: [ + { + messageId: 'doImmediateAction', + data: { + action: 'return', + variable: 'x', + }, + line: 3, + column: 19, + endColumn: 21, }, - line: 3, - column: 19, - endColumn: 21, - }, - ], - output: ` + ], + output: ` function var_returned() { return 42 }`, - }, - { - // hoisted variables - code: ` + }, + { + // hoisted variables + code: ` function foo() { if (cond) { var x = 42; @@ -523,25 +524,25 @@ describe('S1488', () => { } } `, - errors: [ - { - messageId: 'doImmediateAction', - data: { - action: 'return', - variable: 'x', + errors: [ + { + messageId: 'doImmediateAction', + data: { + action: 'return', + variable: 'x', + }, }, - }, - ], - output: ` + ], + output: ` function foo() { if (cond) { return 42; } } `, - }, - { - code: ` + }, + { + code: ` function var_returned() { // comment1 var x /* commentInTheMiddle1 */ = 42; // commentOnTheLine1 @@ -549,19 +550,19 @@ describe('S1488', () => { return /* commentInTheMiddle2 */ x; // commentOnTheLine2 // comment3 }`, - errors: [ - { - messageId: 'doImmediateAction', - data: { - action: 'return', - variable: 'x', + errors: [ + { + messageId: 'doImmediateAction', + data: { + action: 'return', + variable: 'x', + }, + line: 4, + column: 45, + endColumn: 47, }, - line: 4, - column: 45, - endColumn: 47, - }, - ], - output: ` + ], + output: ` function var_returned() { // comment1 // commentOnTheLine1 @@ -569,7 +570,8 @@ describe('S1488', () => { return /* commentInTheMiddle2 */ 42; // commentOnTheLine2 // comment3 }`, - }, - ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1515/unit.test.ts b/packages/jsts/src/rules/S1515/unit.test.ts index b3cc6f3ecf..24f47cd38b 100644 --- a/packages/jsts/src/rules/S1515/unit.test.ts +++ b/packages/jsts/src/rules/S1515/unit.test.ts @@ -16,14 +16,15 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1515', () => { - const ruleTester = new RuleTester(); - ruleTester.run(`Functions should not be defined inside loops`, rule, { - valid: [ - { - code: ` + it('S1515', () => { + const ruleTester = new RuleTester(); + ruleTester.run(`Functions should not be defined inside loops`, rule, { + valid: [ + { + code: ` for (var i = 0; i < 10; i++) { funs[i] = function(i) { // OK, no variable from outer scope is used return i; @@ -35,9 +36,9 @@ describe('S1515', () => { return i; }; `, - }, - { - code: ` + }, + { + code: ` for (var i = 0; i < 10; i++) { funs[i] = function() { // OK, no variable from outer scope is used var x = 42; @@ -58,18 +59,18 @@ describe('S1515', () => { } } `, - }, - { - code: ` + }, + { + code: ` for (let i = 0; i < 13; i++) { funs[i] = function() { // Ok, 'let' declaration return i; }; } `, - }, - { - code: ` + }, + { + code: ` function value_written_once() { var constValue = 42; for (let i = 0; i < 13; i++) { @@ -78,9 +79,9 @@ describe('S1515', () => { }; } }`, - }, - { - code: ` + }, + { + code: ` class A { foo() {} @@ -94,9 +95,9 @@ describe('S1515', () => { } } `, - }, - { - code: ` + }, + { + code: ` function some_callbacks_ok() { for (var i = 0; i < 13; i++) { @@ -155,9 +156,9 @@ describe('S1515', () => { } } `, - }, - { - code: ` + }, + { + code: ` function iife_ok() { for (var i = 0; i < 13; i++) { @@ -170,9 +171,9 @@ describe('S1515', () => { }).call(this); } }`, - }, - { - code: ` + }, + { + code: ` var timeout = 5000; while (true) { new Promise((resolve) => setTimeout(resolve, timeout)) @@ -184,9 +185,9 @@ describe('S1515', () => { }; } `, - }, - { - code: ` + }, + { + code: ` const object = {a: 1, b: 2, c: 3}; for (const property in object) { funs[i] = function() { // OK @@ -194,11 +195,11 @@ describe('S1515', () => { }; } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` var funs = []; for (var i = 0; i < 13; i++) { @@ -235,85 +236,85 @@ describe('S1515', () => { }; } `, - errors: [ - { - message: JSON.stringify({ - message: `Make sure this function is not called after the loop completes.`, - secondaryLocations: [ - { - column: 10, - line: 4, - endColumn: 13, - endLine: 4, - }, - ], - }), - line: 5, - endLine: 5, - column: 23, - endColumn: 31, - }, - { - message: JSON.stringify({ - message: `Make sure this function is not called after the loop completes.`, - secondaryLocations: [ - { - column: 10, - line: 10, - endColumn: 13, - endLine: 10, - }, - ], - }), - line: 12, - }, - { - message: JSON.stringify({ - message: `Make sure this function is not called after the loop completes.`, - secondaryLocations: [ - { - column: 10, - line: 18, - endColumn: 15, - endLine: 18, - }, - ], - }), - line: 19, - }, - { - message: JSON.stringify({ - message: `Make sure this function is not called after the loop completes.`, - secondaryLocations: [ - { - column: 12, - line: 28, - endColumn: 17, - endLine: 28, - }, - ], - }), - line: 25, - }, - { - message: JSON.stringify({ - message: `Make sure this function is not called after the loop completes.`, - secondaryLocations: [ - { - column: 10, - line: 32, - endColumn: 13, - endLine: 32, - }, - ], - }), - line: 33, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `Make sure this function is not called after the loop completes.`, + secondaryLocations: [ + { + column: 10, + line: 4, + endColumn: 13, + endLine: 4, + }, + ], + }), + line: 5, + endLine: 5, + column: 23, + endColumn: 31, + }, + { + message: JSON.stringify({ + message: `Make sure this function is not called after the loop completes.`, + secondaryLocations: [ + { + column: 10, + line: 10, + endColumn: 13, + endLine: 10, + }, + ], + }), + line: 12, + }, + { + message: JSON.stringify({ + message: `Make sure this function is not called after the loop completes.`, + secondaryLocations: [ + { + column: 10, + line: 18, + endColumn: 15, + endLine: 18, + }, + ], + }), + line: 19, + }, + { + message: JSON.stringify({ + message: `Make sure this function is not called after the loop completes.`, + secondaryLocations: [ + { + column: 12, + line: 28, + endColumn: 17, + endLine: 28, + }, + ], + }), + line: 25, + }, + { + message: JSON.stringify({ + message: `Make sure this function is not called after the loop completes.`, + secondaryLocations: [ + { + column: 10, + line: 32, + endColumn: 13, + endLine: 32, + }, + ], + }), + line: 33, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` var funs = []; for (var i = 0; i < 13; i++) { @@ -322,15 +323,15 @@ describe('S1515', () => { }; } `, - errors: [ - { - message: 'Make sure this function is not called after the loop completes.', - line: 5, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Make sure this function is not called after the loop completes.', + line: 5, + }, + ], + }, + { + code: ` function value_written_once() { for (let i = 0; i < 13; i++) { @@ -349,10 +350,10 @@ describe('S1515', () => { } } `, - errors: 2, - }, - { - code: ` + errors: 2, + }, + { + code: ` for (var i = 0; i < 10; i++) { var x = 42; funs[i] = function() { // Noncompliant, x is in the loop scope @@ -363,10 +364,10 @@ describe('S1515', () => { } } `, - errors: 2, - }, - { - code: ` + errors: 2, + }, + { + code: ` function some_callbacks_not_ok() { for (var i = 0; i < 13; i++) { arr.unknown(function() { // Noncompliant @@ -379,18 +380,18 @@ describe('S1515', () => { } } `, - errors: 2, - }, - { - code: ` + errors: 2, + }, + { + code: ` while (true) { var timeout = 5000; new Promise((resolve) => setTimeout(resolve, timeout)) // Noncompliant }`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` for (var i = 0; i < 10; i++) { funs[i] = (function() { return function() { // Noncompliant @@ -406,17 +407,18 @@ describe('S1515', () => { }; }(i)); }`, - errors: [ - { - message: 'Make sure this function is not called after the loop completes.', - line: 4, - }, - { - message: 'Make sure this function is not called after the loop completes.', - line: 12, - }, - ], - }, - ], + errors: [ + { + message: 'Make sure this function is not called after the loop completes.', + line: 4, + }, + { + message: 'Make sure this function is not called after the loop completes.', + line: 12, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1523/unit.test.ts b/packages/jsts/src/rules/S1523/unit.test.ts index 3710dd9cd8..f2241a3d9c 100644 --- a/packages/jsts/src/rules/S1523/unit.test.ts +++ b/packages/jsts/src/rules/S1523/unit.test.ts @@ -16,94 +16,96 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1523', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Dynamically executing code is security-sensitive', rule, { - valid: [ - { - code: `foo(x)`, - }, - { - code: `function foo(x){}\n foo(x);`, - }, - { - code: `eval()`, - }, - { - code: `eval(42)`, - }, - { - code: `eval("Hello")`, - }, - { - code: `eval(\`Hello\`)`, - }, - { - code: `Function()`, - }, - { - code: `new Function(42)`, - }, - { - code: `new Function('a', 42)`, - }, - { - code: `Function(42, 'x')`, - }, - { - code: `Function("Hello")`, - }, - { - code: `Function(\`Hello\`)`, - }, - ], - invalid: [ - { - code: `eval(x);`, - errors: [ - { - message: 'Make sure that this dynamic injection or execution of code is safe.', - line: 1, - endLine: 1, - column: 1, - endColumn: 5, - }, - ], - }, - { - code: `eval(\`Hello \${x}\`)`, - errors: 1, - }, - { - code: `Function(x)`, - errors: 1, - }, - { - code: `new Function(x)`, - errors: 1, - }, - { - code: `eval(42, x)`, - errors: 1, - }, - { - code: `eval(x, 42)`, - errors: 1, - }, - { - code: `new Function(a, x)`, - errors: 1, - }, - { - code: `new Function('a', x)`, - errors: 1, - }, - { - code: `location.href = 'javascript: void(0)';`, - errors: 1, - }, - ], + it('S1523', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Dynamically executing code is security-sensitive', rule, { + valid: [ + { + code: `foo(x)`, + }, + { + code: `function foo(x){}\n foo(x);`, + }, + { + code: `eval()`, + }, + { + code: `eval(42)`, + }, + { + code: `eval("Hello")`, + }, + { + code: `eval(\`Hello\`)`, + }, + { + code: `Function()`, + }, + { + code: `new Function(42)`, + }, + { + code: `new Function('a', 42)`, + }, + { + code: `Function(42, 'x')`, + }, + { + code: `Function("Hello")`, + }, + { + code: `Function(\`Hello\`)`, + }, + ], + invalid: [ + { + code: `eval(x);`, + errors: [ + { + message: 'Make sure that this dynamic injection or execution of code is safe.', + line: 1, + endLine: 1, + column: 1, + endColumn: 5, + }, + ], + }, + { + code: `eval(\`Hello \${x}\`)`, + errors: 1, + }, + { + code: `Function(x)`, + errors: 1, + }, + { + code: `new Function(x)`, + errors: 1, + }, + { + code: `eval(42, x)`, + errors: 1, + }, + { + code: `eval(x, 42)`, + errors: 1, + }, + { + code: `new Function(a, x)`, + errors: 1, + }, + { + code: `new Function('a', x)`, + errors: 1, + }, + { + code: `location.href = 'javascript: void(0)';`, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1526/unit.test.ts b/packages/jsts/src/rules/S1526/unit.test.ts index 190a7d90f9..453cde8ad7 100644 --- a/packages/jsts/src/rules/S1526/unit.test.ts +++ b/packages/jsts/src/rules/S1526/unit.test.ts @@ -16,117 +16,119 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1526', () => { - const ruleTester = new RuleTester(); + it('S1526', () => { + const ruleTester = new RuleTester(); - ruleTester.run(`Variables declared with "var" should be declared before they are used`, rule, { - valid: [ - { - code: `var x;`, - }, - { - code: ` + ruleTester.run(`Variables declared with "var" should be declared before they are used`, rule, { + valid: [ + { + code: `var x;`, + }, + { + code: ` var x; print(x); `, - }, - { - code: ` + }, + { + code: ` function fun(x) { print(x); } `, - }, - { - code: ` + }, + { + code: ` print(x); let x = 1; `, - }, - { - code: ` + }, + { + code: ` print(x); const x = 1; `, - }, - { - code: ` + }, + { + code: ` for (var x of xs) {} var x; `, - }, - { - code: ` + }, + { + code: ` for (var x of xs) {} x; `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` print(x); var x = 1; `, - errors: [ - { - message: `{"message":"Move the declaration of \\\"x\\\" before this usage.","secondaryLocations":[{"message":"Declaration","column":10,"line":3,"endColumn":11,"endLine":3}]}`, - line: 2, - endLine: 2, - column: 13, - endColumn: 14, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: `{"message":"Move the declaration of \\\"x\\\" before this usage.","secondaryLocations":[{"message":"Declaration","column":10,"line":3,"endColumn":11,"endLine":3}]}`, + line: 2, + endLine: 2, + column: 13, + endColumn: 14, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` print(x); println(x); var x = 1; `, - errors: [ - { - message: `{"message":"Move the declaration of \\\"x\\\" before this usage.","secondaryLocations":[{"message":"Declaration","column":10,"line":4,"endColumn":11,"endLine":4}]}`, - line: 2, - endLine: 2, - column: 13, - endColumn: 14, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: `{"message":"Move the declaration of \\\"x\\\" before this usage.","secondaryLocations":[{"message":"Declaration","column":10,"line":4,"endColumn":11,"endLine":4}]}`, + line: 2, + endLine: 2, + column: 13, + endColumn: 14, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` print(x); var x; `, - errors: 1, - }, - { - code: `print(x); var x;`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: `print(x); var x;`, + errors: 1, + }, + { + code: ` function fun() { print(x); } var x; `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` let fun = () => { print(x); } var x; `, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1527/unit.test.ts b/packages/jsts/src/rules/S1527/unit.test.ts index cdd5cd5fab..df028a38e5 100644 --- a/packages/jsts/src/rules/S1527/unit.test.ts +++ b/packages/jsts/src/rules/S1527/unit.test.ts @@ -16,28 +16,29 @@ */ import { DefaultParserRuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1527', () => { - const ruleTester = new DefaultParserRuleTester({ - sourceType: 'script', - parserOptions: { ecmaVersion: 3, allowReserved: true }, - }); + it('S1527', () => { + const ruleTester = new DefaultParserRuleTester({ + sourceType: 'script', + parserOptions: { ecmaVersion: 3, allowReserved: true }, + }); - ruleTester.run('Future reserved words', rule, { - valid: [ - { - code: ` + ruleTester.run('Future reserved words', rule, { + valid: [ + { + code: ` var _interface = { implements: true }; if (_interface.implements) {} `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` var implements; // NOK implements = 42; // ok, usage @@ -51,40 +52,41 @@ describe('S1527', () => { var extends; // NOK } `, - errors: [ - { - message: `Rename "implements" identifier to prevent potential conflicts with future evolutions of the JavaScript language.`, - line: 2, - endLine: 2, - column: 11, - endColumn: 21, - }, - { - message: `Rename "interface" identifier to prevent potential conflicts with future evolutions of the JavaScript language.`, - line: 7, - }, - { - messageId: 'renameReserved', - line: 8, - }, - { - messageId: 'renameReserved', - line: 9, - }, - { - messageId: 'renameReserved', - line: 10, - }, - { - messageId: 'renameReserved', - line: 11, - }, - { - messageId: 'renameReserved', - line: 12, - }, - ], - }, - ], + errors: [ + { + message: `Rename "implements" identifier to prevent potential conflicts with future evolutions of the JavaScript language.`, + line: 2, + endLine: 2, + column: 11, + endColumn: 21, + }, + { + message: `Rename "interface" identifier to prevent potential conflicts with future evolutions of the JavaScript language.`, + line: 7, + }, + { + messageId: 'renameReserved', + line: 8, + }, + { + messageId: 'renameReserved', + line: 9, + }, + { + messageId: 'renameReserved', + line: 10, + }, + { + messageId: 'renameReserved', + line: 11, + }, + { + messageId: 'renameReserved', + line: 12, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1528/unit.test.ts b/packages/jsts/src/rules/S1528/unit.test.ts index 9c1fed3990..77fd0da684 100644 --- a/packages/jsts/src/rules/S1528/unit.test.ts +++ b/packages/jsts/src/rules/S1528/unit.test.ts @@ -16,105 +16,107 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1528', () => { - const eslintRuleTester = new RuleTester(); + it('S1528', () => { + const eslintRuleTester = new RuleTester(); - const typeScriptRuleTester = new RuleTester(); - const testCases = { - valid: [ - { - code: ` + const typeScriptRuleTester = new RuleTester(); + const testCases = { + valid: [ + { + code: ` var o = new Object(); `, - }, - { - code: ` + }, + { + code: ` var a1 = [x1, x2, x3];; `, - }, - { - code: ` + }, + { + code: ` var a2 = []; `, - }, - { - code: ` + }, + { + code: ` let unstableArray = Array.from({length: n}); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` var a = new Array(x1, x2, x3); `, - errors: [ - { - message: 'Use either a literal or "Array.from()" instead of the "Array" constructor.', - line: 2, - endLine: 2, - column: 21, - endColumn: 42, - suggestions: [ - { - desc: 'Replace with a literal', - output: ` + errors: [ + { + message: 'Use either a literal or "Array.from()" instead of the "Array" constructor.', + line: 2, + endLine: 2, + column: 21, + endColumn: 42, + suggestions: [ + { + desc: 'Replace with a literal', + output: ` var a = [x1, x2, x3]; `, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` myArray = new Array(foo + 2).join('#'); `, - errors: [ - { - message: 'Use either a literal or "Array.from()" instead of the "Array" constructor.', - line: 2, - endLine: 2, - column: 23, - endColumn: 41, - suggestions: [ - { - desc: 'Replace with "Array.from()"', - output: ` + errors: [ + { + message: 'Use either a literal or "Array.from()" instead of the "Array" constructor.', + line: 2, + endLine: 2, + column: 23, + endColumn: 41, + suggestions: [ + { + desc: 'Replace with "Array.from()"', + output: ` myArray = Array.from({length: foo + 2}).join('#'); `, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` myArray = new Array(42).join('#'); `, - errors: [ - { - message: 'Use "Array.from()" instead of the "Array" constructor.', - line: 2, - endLine: 2, - column: 23, - endColumn: 36, - suggestions: [ - { - desc: 'Replace with "Array.from()"', - output: ` + errors: [ + { + message: 'Use "Array.from()" instead of the "Array" constructor.', + line: 2, + endLine: 2, + column: 23, + endColumn: 36, + suggestions: [ + { + desc: 'Replace with "Array.from()"', + output: ` myArray = Array.from({length: 42}).join('#'); `, - }, - ], - }, - ], - }, - ], - }; + }, + ], + }, + ], + }, + ], + }; - eslintRuleTester.run('JS: Array constructor should not be used', rule, testCases); - typeScriptRuleTester.run('TS: Array constructor should not be used', rule, testCases); + eslintRuleTester.run('JS: Array constructor should not be used', rule, testCases); + typeScriptRuleTester.run('TS: Array constructor should not be used', rule, testCases); + }); }); diff --git a/packages/jsts/src/rules/S1529/unit.test.ts b/packages/jsts/src/rules/S1529/unit.test.ts index bc9e635b93..01a86c60f9 100644 --- a/packages/jsts/src/rules/S1529/unit.test.ts +++ b/packages/jsts/src/rules/S1529/unit.test.ts @@ -16,128 +16,129 @@ */ import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1529', () => { - const ruleTesterJs = new DefaultParserRuleTester(); + it('S1529', () => { + const ruleTesterJs = new DefaultParserRuleTester(); - const ruleTesterTs = new RuleTester(); + const ruleTesterTs = new RuleTester(); - ruleTesterJs.run(`JS: Bitwise operators should not be used in boolean contexts`, rule, { - valid: [ - { - code: `// ok with numeric literal + ruleTesterJs.run(`JS: Bitwise operators should not be used in boolean contexts`, rule, { + valid: [ + { + code: `// ok with numeric literal let a = 1; if (a & 1) { } `, - }, - ], - invalid: [ - { - code: `// not ok, FP because javascript parser has no type information, no issue with typescript parser + }, + ], + invalid: [ + { + code: `// not ok, FP because javascript parser has no type information, no issue with typescript parser let a = 1; let b = 1; if (a & b) { } `, - errors: [ - { - message: - 'Review this use of bitwise "&" operator; conditional "&&" might have been intended.', - line: 4, - endLine: 4, - column: 7, - endColumn: 8, - }, - ], - }, - ], - }); + errors: [ + { + message: + 'Review this use of bitwise "&" operator; conditional "&&" might have been intended.', + line: 4, + endLine: 4, + column: 7, + endColumn: 8, + }, + ], + }, + ], + }); - ruleTesterTs.run(`TS: Bitwise operators should not be used in boolean contexts`, rule, { - valid: [ - { - code: `// ok with numeric type number + ruleTesterTs.run(`TS: Bitwise operators should not be used in boolean contexts`, rule, { + valid: [ + { + code: `// ok with numeric type number let a = 1; let b = 5; if (a & b) { } `, - }, - { - code: `// ok with numeric type bigint + }, + { + code: `// ok with numeric type bigint function f(a: bigint | number, b: any) { if (a & b) { } } `, - }, - { - code: `// ok with numeric type in an union + }, + { + code: `// ok with numeric type in an union function f(a: bigint | string, b: any) { if (a & b) { } } `, - }, - { - code: `// ok with numeric type of an enum + }, + { + code: `// ok with numeric type of an enum enum Direction { Up = 1, Down } let b = Direction.Up; if (a & b) { } `, - }, - { - code: `// ok for init + }, + { + code: `// ok for init for (x = a & b; x < 10; x++) { // OK, not condition } `, - }, - { - code: `// ok for no condition + }, + { + code: `// ok for no condition for (x = a & b; ; x++) { // OK, not condition } `, - }, - { - code: `// ok outside condition + }, + { + code: `// ok outside condition foo(a & b); // OK, not inside condition foo(a + b); `, - }, - { - code: `// file ok several suspicious + }, + { + code: `// file ok several suspicious if (a & b) { // OK, as there are 2 operations "&" and "|" on line 5 } if (a | c) { } `, - }, - { - code: `// ok with bitwise operator + }, + { + code: `// ok with bitwise operator if (a & b) { // OK, as ">>>" is used further } a = x >>> y; `, - }, - { - code: `// ok with literal + }, + { + code: `// ok with literal if (a & b) { // OK, as "|" is used as bitwise further } if (a | 1) { } `, - }, - ], - invalid: [ - { - code: `// not ok with type "any" + }, + ], + invalid: [ + { + code: `// not ok with type "any" function f(a: any, b: any) { if (a | b) { } @@ -145,85 +146,86 @@ function f(a: any, b: any) { const c: string | number = 2; } `, - errors: [ - { - message: - 'Review this use of bitwise "|" operator; conditional "||" might have been intended.', - line: 3, - endLine: 3, - column: 11, - endColumn: 12, - }, - ], - }, - { - code: `// not ok do while + errors: [ + { + message: + 'Review this use of bitwise "|" operator; conditional "||" might have been intended.', + line: 3, + endLine: 3, + column: 11, + endColumn: 12, + }, + ], + }, + { + code: `// not ok do while do { } while (a /*comment*/ | b); // Noncompliant a = x && y; `, - errors: [ - { - message: - 'Review this use of bitwise "|" operator; conditional "||" might have been intended.', - line: 3, - endLine: 3, - column: 24, - endColumn: 25, - }, - ], - }, - { - code: `// not ok if + errors: [ + { + message: + 'Review this use of bitwise "|" operator; conditional "||" might have been intended.', + line: 3, + endLine: 3, + column: 24, + endColumn: 25, + }, + ], + }, + { + code: `// not ok if if (a & b) { // Noncompliant } a = x && y; `, - errors: [ - { - message: - 'Review this use of bitwise "&" operator; conditional "&&" might have been intended.', - line: 2, - endLine: 2, - column: 7, - endColumn: 8, - }, - ], - }, - { - code: `// not ok ternary + errors: [ + { + message: + 'Review this use of bitwise "&" operator; conditional "&&" might have been intended.', + line: 2, + endLine: 2, + column: 7, + endColumn: 8, + }, + ], + }, + { + code: `// not ok ternary x = a & b ? 1 : 2; // Noncompliant a = x && y; `, - errors: [ - { - message: - 'Review this use of bitwise "&" operator; conditional "&&" might have been intended.', - line: 2, - endLine: 2, - column: 7, - endColumn: 8, - }, - ], - }, - { - code: `// not ok while + errors: [ + { + message: + 'Review this use of bitwise "&" operator; conditional "&&" might have been intended.', + line: 2, + endLine: 2, + column: 7, + endColumn: 8, + }, + ], + }, + { + code: `// not ok while while ((a | b) && c) { // Noncompliant // ^ } a = x && y; `, - errors: [ - { - message: - 'Review this use of bitwise "|" operator; conditional "||" might have been intended.', - line: 2, - endLine: 2, - column: 11, - endColumn: 12, - }, - ], - }, - ], + errors: [ + { + message: + 'Review this use of bitwise "|" operator; conditional "||" might have been intended.', + line: 2, + endLine: 2, + column: 11, + endColumn: 12, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1530/unit.test.ts b/packages/jsts/src/rules/S1530/unit.test.ts index 9c7543bd6e..0c29db11b6 100644 --- a/packages/jsts/src/rules/S1530/unit.test.ts +++ b/packages/jsts/src/rules/S1530/unit.test.ts @@ -16,14 +16,15 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1530', () => { - const ruleTester = new RuleTester(); - ruleTester.run(`Function declarations should not be made within blocks`, rule, { - valid: [ - { - code: ` + it('S1530', () => { + const ruleTester = new RuleTester(); + ruleTester.run(`Function declarations should not be made within blocks`, rule, { + valid: [ + { + code: ` if (x) { let foo; foo = function() {} // OK @@ -47,56 +48,57 @@ describe('S1530', () => { function nested() { } // OK } }`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` if (x) { function foo() { } }`, - errors: [ - { - message: `Do not use function declarations within blocks.`, - line: 3, - column: 18, - endLine: 3, - endColumn: 21, - }, - ], - }, - ], - }); + errors: [ + { + message: `Do not use function declarations within blocks.`, + line: 3, + column: 18, + endLine: 3, + endColumn: 21, + }, + ], + }, + ], + }); - const ruleTesterTS = new RuleTester(); + const ruleTesterTS = new RuleTester(); - ruleTesterTS.run(`Function declarations should not be made within blocks`, rule, { - valid: [ - { - code: ` + ruleTesterTS.run(`Function declarations should not be made within blocks`, rule, { + valid: [ + { + code: ` interface I { isOk(): boolean; }`, - }, - { - code: ` + }, + { + code: ` namespace space { function f() {} export function f2() {} }`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` namespace space { if (x) { function foo() {} } }`, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1533/unit.test.ts b/packages/jsts/src/rules/S1533/unit.test.ts index cf31e8349e..8f52d4ddfb 100644 --- a/packages/jsts/src/rules/S1533/unit.test.ts +++ b/packages/jsts/src/rules/S1533/unit.test.ts @@ -16,15 +16,16 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1533', () => { - const ruleTester = new RuleTester(); + it('S1533', () => { + const ruleTester = new RuleTester(); - ruleTester.run('Wrapper objects should not be used for primitive types', rule, { - valid: [ - { - code: ` + ruleTester.run('Wrapper objects should not be used for primitive types', rule, { + valid: [ + { + code: ` // not primitive wrapper constructors x = new Array(); x = new MyObject(); @@ -41,217 +42,218 @@ describe('S1533', () => { const c: number = 3; function myFunction(param1: boolean, param2: string): boolean { return true; }`, - }, - ], - invalid: [ - { - code: `x = new Number;`, - errors: [ - { - message: 'Remove this use of "Number" constructor.', - line: 1, - endLine: 1, - column: 5, - endColumn: 15, - suggestions: [ - { - output: 'x = Number;', - desc: 'Remove "new" operator', - }, - ], - }, - ], - }, - { - code: `x = new Number(y);`, - errors: [ - { - message: 'Remove this use of "Number" constructor.', - line: 1, - endLine: 1, - column: 5, - endColumn: 18, - suggestions: [ - { - output: 'x = Number(y);', - desc: 'Remove "new" operator', - }, - ], - }, - ], - }, - { - code: `x = new String("str");`, - errors: [ - { - message: 'Remove this use of "String" constructor.', - line: 1, - endLine: 1, - column: 5, - endColumn: 22, - suggestions: [ - { - output: 'x = String("str");', - desc: 'Remove "new" operator', - }, - ], - }, - ], - }, - { - code: `x = new String("str", 42);`, - errors: [ - { - message: 'Remove this use of "String" constructor.', - line: 1, - endLine: 1, - column: 5, - endColumn: 26, - suggestions: [ - { - output: 'x = String("str", 42);', - desc: 'Remove "new" operator', - }, - ], - }, - ], - }, - { - code: `let y: number | Boolean | string;`, - errors: [ - { - message: 'Replace this "Boolean" wrapper object with primitive type "boolean".', - line: 1, - endLine: 1, - column: 17, - endColumn: 24, - suggestions: [ - { - output: 'let y: number | boolean | string;', - desc: 'Replace "Boolean" with "boolean"', - }, - ], - }, - ], - }, - { - code: `function myFunction(param1: boolean, param2: String): Number { return true; }`, - errors: [ - { - message: 'Replace this "String" wrapper object with primitive type "string".', - line: 1, - endLine: 1, - column: 46, - endColumn: 52, - suggestions: [ - { - output: - 'function myFunction(param1: boolean, param2: string): Number { return true; }', - desc: 'Replace "String" with "string"', - }, - ], - }, - { - message: 'Replace this "Number" wrapper object with primitive type "number".', - line: 1, - endLine: 1, - column: 55, - endColumn: 61, - suggestions: [ - { - output: - 'function myFunction(param1: boolean, param2: String): number { return true; }', - desc: 'Replace "Number" with "number"', - }, - ], - }, - ], - }, - { - code: `x = new Boolean(true);`, - errors: [ - { - message: 'Remove this use of "Boolean" constructor.', - suggestions: [ - { - output: 'x = Boolean(true);', - desc: 'Remove "new" operator', - }, - ], - }, - ], - }, - { - code: `x = new Boolean(false);`, - errors: [ - { - message: 'Remove this use of "Boolean" constructor.', - suggestions: [ - { - output: 'x = Boolean(false);', - desc: 'Remove "new" operator', - }, - ], - }, - ], - }, - { - code: `let y: String;`, - errors: [ - { - message: 'Replace this "String" wrapper object with primitive type "string".', - suggestions: [ - { - output: 'let y: string;', - desc: 'Replace "String" with "string"', - }, - ], - }, - ], - }, - { - code: ` + }, + ], + invalid: [ + { + code: `x = new Number;`, + errors: [ + { + message: 'Remove this use of "Number" constructor.', + line: 1, + endLine: 1, + column: 5, + endColumn: 15, + suggestions: [ + { + output: 'x = Number;', + desc: 'Remove "new" operator', + }, + ], + }, + ], + }, + { + code: `x = new Number(y);`, + errors: [ + { + message: 'Remove this use of "Number" constructor.', + line: 1, + endLine: 1, + column: 5, + endColumn: 18, + suggestions: [ + { + output: 'x = Number(y);', + desc: 'Remove "new" operator', + }, + ], + }, + ], + }, + { + code: `x = new String("str");`, + errors: [ + { + message: 'Remove this use of "String" constructor.', + line: 1, + endLine: 1, + column: 5, + endColumn: 22, + suggestions: [ + { + output: 'x = String("str");', + desc: 'Remove "new" operator', + }, + ], + }, + ], + }, + { + code: `x = new String("str", 42);`, + errors: [ + { + message: 'Remove this use of "String" constructor.', + line: 1, + endLine: 1, + column: 5, + endColumn: 26, + suggestions: [ + { + output: 'x = String("str", 42);', + desc: 'Remove "new" operator', + }, + ], + }, + ], + }, + { + code: `let y: number | Boolean | string;`, + errors: [ + { + message: 'Replace this "Boolean" wrapper object with primitive type "boolean".', + line: 1, + endLine: 1, + column: 17, + endColumn: 24, + suggestions: [ + { + output: 'let y: number | boolean | string;', + desc: 'Replace "Boolean" with "boolean"', + }, + ], + }, + ], + }, + { + code: `function myFunction(param1: boolean, param2: String): Number { return true; }`, + errors: [ + { + message: 'Replace this "String" wrapper object with primitive type "string".', + line: 1, + endLine: 1, + column: 46, + endColumn: 52, + suggestions: [ + { + output: + 'function myFunction(param1: boolean, param2: string): Number { return true; }', + desc: 'Replace "String" with "string"', + }, + ], + }, + { + message: 'Replace this "Number" wrapper object with primitive type "number".', + line: 1, + endLine: 1, + column: 55, + endColumn: 61, + suggestions: [ + { + output: + 'function myFunction(param1: boolean, param2: String): number { return true; }', + desc: 'Replace "Number" with "number"', + }, + ], + }, + ], + }, + { + code: `x = new Boolean(true);`, + errors: [ + { + message: 'Remove this use of "Boolean" constructor.', + suggestions: [ + { + output: 'x = Boolean(true);', + desc: 'Remove "new" operator', + }, + ], + }, + ], + }, + { + code: `x = new Boolean(false);`, + errors: [ + { + message: 'Remove this use of "Boolean" constructor.', + suggestions: [ + { + output: 'x = Boolean(false);', + desc: 'Remove "new" operator', + }, + ], + }, + ], + }, + { + code: `let y: String;`, + errors: [ + { + message: 'Replace this "String" wrapper object with primitive type "string".', + suggestions: [ + { + output: 'let y: string;', + desc: 'Replace "String" with "string"', + }, + ], + }, + ], + }, + { + code: ` x = new Number(true); x = new Number(false); x = new Number(0);`, - errors: 3, - }, - { - code: ` + errors: 3, + }, + { + code: ` x = new String(y); x = new String(42); x = new String(); x = new String("");`, - errors: 4, - }, - { - code: `x = new Number(true);`, - errors: [ - { - message: 'Remove this use of "Number" constructor.', - suggestions: [ - { - desc: 'Remove "new" operator', - output: 'x = Number(true);', - }, - ], - }, - ], - }, - { - code: `function foo(): Number {}`, - errors: [ - { - messageId: 'replaceWrapper', - suggestions: [ - { - desc: 'Replace "Number" with "number"', - output: 'function foo(): number {}', - }, - ], - }, - ], - }, - ], + errors: 4, + }, + { + code: `x = new Number(true);`, + errors: [ + { + message: 'Remove this use of "Number" constructor.', + suggestions: [ + { + desc: 'Remove "new" operator', + output: 'x = Number(true);', + }, + ], + }, + ], + }, + { + code: `function foo(): Number {}`, + errors: [ + { + messageId: 'replaceWrapper', + suggestions: [ + { + desc: 'Replace "Number" with "number"', + output: 'function foo(): number {}', + }, + ], + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1534/unit.test.ts b/packages/jsts/src/rules/S1534/unit.test.ts index 8a51a50037..99bd6f26aa 100644 --- a/packages/jsts/src/rules/S1534/unit.test.ts +++ b/packages/jsts/src/rules/S1534/unit.test.ts @@ -16,92 +16,96 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1534', () => { - const ruleTester = new RuleTester(); - ruleTester.run(`Decorated rule should provide suggestion`, rule, { - valid: [ - { - code: `let x = { a: 42, b: 42 }`, - }, - ], - invalid: [ - { - code: `let x = { a: 42, a: 42 }`, - errors: [ - { - message: "Duplicate name 'a'.", - suggestions: [{ output: `let x = { a: 42 }`, desc: 'Remove this duplicate property' }], - }, - ], - }, - { - code: `let x = { a: 42, a: 42, b: 42 }`, - errors: [ - { - message: "Duplicate name 'a'.", - suggestions: [ - { output: `let x = { a: 42, b: 42 }`, desc: 'Remove this duplicate property' }, - ], - }, - ], - }, - { - code: `let x = { a: 42, b: 42, a: 42, }`, - errors: [ - { - message: "Duplicate name 'a'.", - suggestions: [ - { output: `let x = { a: 42, b: 42, }`, desc: 'Remove this duplicate property' }, - ], - }, - ], - }, - { - code: ` + it('S1534', () => { + const ruleTester = new RuleTester(); + ruleTester.run(`Decorated rule should provide suggestion`, rule, { + valid: [ + { + code: `let x = { a: 42, b: 42 }`, + }, + ], + invalid: [ + { + code: `let x = { a: 42, a: 42 }`, + errors: [ + { + message: "Duplicate name 'a'.", + suggestions: [ + { output: `let x = { a: 42 }`, desc: 'Remove this duplicate property' }, + ], + }, + ], + }, + { + code: `let x = { a: 42, a: 42, b: 42 }`, + errors: [ + { + message: "Duplicate name 'a'.", + suggestions: [ + { output: `let x = { a: 42, b: 42 }`, desc: 'Remove this duplicate property' }, + ], + }, + ], + }, + { + code: `let x = { a: 42, b: 42, a: 42, }`, + errors: [ + { + message: "Duplicate name 'a'.", + suggestions: [ + { output: `let x = { a: 42, b: 42, }`, desc: 'Remove this duplicate property' }, + ], + }, + ], + }, + { + code: ` let x = { a: 42, a: 42 }`, - errors: [ - { - message: "Duplicate name 'a'.", - suggestions: [ - { - output: ` + errors: [ + { + message: "Duplicate name 'a'.", + suggestions: [ + { + output: ` let x = { a: 42 }`, - desc: 'Remove this duplicate property', - }, - ], - }, - ], - }, - { - code: ` + desc: 'Remove this duplicate property', + }, + ], + }, + ], + }, + { + code: ` let x = { a: 42, get a() { return 42; }, }`, - errors: [ - { - message: "Duplicate name 'a'.", - suggestions: [ - { - output: ` + errors: [ + { + message: "Duplicate name 'a'.", + suggestions: [ + { + output: ` let x = { a: 42, }`, - desc: 'Remove this duplicate property', - }, - ], - }, - ], - }, - ], + desc: 'Remove this duplicate property', + }, + ], + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1535/unit.test.ts b/packages/jsts/src/rules/S1535/unit.test.ts index 57a9132d78..9323586d28 100644 --- a/packages/jsts/src/rules/S1535/unit.test.ts +++ b/packages/jsts/src/rules/S1535/unit.test.ts @@ -16,85 +16,87 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1535', () => { - const ruleTester = new RuleTester(); - ruleTester.run('"for...in" loops should filter properties before acting on them', rule, { - valid: [ - { - code: ` + it('S1535', () => { + const ruleTester = new RuleTester(); + ruleTester.run('"for...in" loops should filter properties before acting on them', rule, { + valid: [ + { + code: ` for (name in object) { if (object.hasOwnProperty(name)) { print(object[name]); } } `, - }, - { - code: ` + }, + { + code: ` for (name in object) { // OK } `, - }, + }, - { - code: ` + { + code: ` for (key in obj) // OK a[key] = b[key]; `, - }, - { - code: ` + }, + { + code: ` for (key in obj) { // OK a[key] = b[key]; } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` for (key in arr) { // Noncompliant {{Restrict what this loop acts on by testing each property.}} print(arr[key]); print(arr[key]); } `, - errors: [ - { - message: 'Restrict what this loop acts on by testing each property.', - line: 2, - endLine: 5, - column: 7, - endColumn: 8, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Restrict what this loop acts on by testing each property.', + line: 2, + endLine: 5, + column: 7, + endColumn: 8, + }, + ], + }, + { + code: ` for (key in arr) { // Noncompliant function f() {} print(arr[key]); } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` for (key in obj) { // Noncompliant val = b[key]; } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` for (key in obj) { // Noncompliant a.b = key; } `, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1541/unit.test.ts b/packages/jsts/src/rules/S1541/unit.test.ts index ea8a7bde19..f1cff4a330 100644 --- a/packages/jsts/src/rules/S1541/unit.test.ts +++ b/packages/jsts/src/rules/S1541/unit.test.ts @@ -17,28 +17,29 @@ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; import { EncodedMessage, IssueLocation } from '../helpers/index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1541', () => { - const ruleTester = new RuleTester(); - const options = [ - { - threshold: 2, - }, - ]; - - ruleTester.run('Functions should not be too complex', rule, { - valid: [ + it('S1541', () => { + const ruleTester = new RuleTester(); + const options = [ { - code: ` + threshold: 2, + }, + ]; + + ruleTester.run('Functions should not be too complex', rule, { + valid: [ + { + code: ` if (x) {} if (x) {} if (x) {} `, - options, - }, - { - code: ` + options, + }, + { + code: ` function ok() { // +1 if (x) { // +1 return 0; // +0 @@ -47,10 +48,10 @@ describe('S1541', () => { } } `, - options, - }, - { - code: ` + options, + }, + { + code: ` function ok() { // OK +1 for ok a = true && false; // +1 for ok b = function foo() { // OK +1 for foo, +0 for ok @@ -60,28 +61,28 @@ describe('S1541', () => { } } `, - options, - }, - { - code: ` + options, + }, + { + code: ` function ok() { // OK +1 for ok a = true && false; // +1 for ok b = arr.map(s => s.length); // OK +0 for ok } `, - options, - }, - { - code: ` + options, + }, + { + code: ` function ok() { // OK +1 for ok a = true && false; // +1 for ok b = () => 10; // OK +0 for ok } `, - options, - }, - { - code: ` + options, + }, + { + code: ` function nesting() { // OK +1 for nesting function nested() { // OK +1 for nested if (x) { // +1 for nested @@ -90,10 +91,10 @@ describe('S1541', () => { } } `, - options, - }, - { - code: ` + options, + }, + { + code: ` function ok() { // OK +1 for ok return { // +0 for ok get x() { // OK +1 for x @@ -102,10 +103,10 @@ describe('S1541', () => { }; } `, - options, - }, - { - code: ` + options, + }, + { + code: ` function ok() { // OK +1 for ok a = true || false; // +1 for ok @@ -113,74 +114,74 @@ describe('S1541', () => { } } `, - options, - }, - { - code: ` + options, + }, + { + code: ` (function(x) { // OK - Immediately Invoked Function Expression if (x) {} if (x) {} if (x) {} })(34); `, - options, - }, - { - code: ` + options, + }, + { + code: ` var a = function () { // OK - Immediately Invoked Function Expression var a = true && false && true; }(); `, - options, - }, - { - code: ` + options, + }, + { + code: ` new (function() { // OK - Immediately Invoked Function Expression var a = true && false && true; })(); `, - options, - }, - { - code: ` + options, + }, + { + code: ` define([], function(){ // AMD PATTERN - OK var a = true && false && true; }); `, - options, - }, - { - code: ` + options, + }, + { + code: ` define([], "module name", function(){ // AMD PATTERN - OK var a = true && false && true; }); `, - options, - }, - // TODO not supported yet - // { - // code: ` - // // ANGULAR JS Exceptions + options, + }, + // TODO not supported yet + // { + // code: ` + // // ANGULAR JS Exceptions - // var moduleX = angular.module("moduleX"); + // var moduleX = angular.module("moduleX"); - // moduleX - // .controller("Name", function() { // OK - // var a = true && false && true; - // }) - // .service("Name", ['$scope', function($scope) { // OK - // var a = true && false && true; - // }]); + // moduleX + // .controller("Name", function() { // OK + // var a = true && false && true; + // }) + // .service("Name", ['$scope', function($scope) { // OK + // var a = true && false && true; + // }]); - // moduleX.config(function() { // OK - // var a = true && false && true; - // }); - // `, - // options, - // }, - ], - invalid: [ - invalid(` + // moduleX.config(function() { // OK + // var a = true && false && true; + // }); + // `, + // options, + // }, + ], + invalid: [ + invalid(` function ko() { //P^^ if (x) {} @@ -190,7 +191,7 @@ describe('S1541', () => { else {} } `), - invalid(` + invalid(` function ko() { //P^^ if (x) {} @@ -203,7 +204,7 @@ describe('S1541', () => { //^^ } `), - invalid(` + invalid(` function * ko() { //P^^ if (x) {} @@ -212,7 +213,7 @@ describe('S1541', () => { //^^ } `), - invalid(` + invalid(` function * ko() { //P^^ if (x) { @@ -222,7 +223,7 @@ describe('S1541', () => { } } `), - invalid(` + invalid(` function ko(x) { //P^^ switch (x) { @@ -240,7 +241,7 @@ describe('S1541', () => { } } `), - invalid(` + invalid(` function ko() { //P^^ a = true && false; @@ -249,7 +250,7 @@ describe('S1541', () => { //^^ } `), - invalid(` + invalid(` function nesting() { function nested() { //P^^^^^^ @@ -261,7 +262,7 @@ describe('S1541', () => { } } `), - invalid(` + invalid(` function nesting1() { function nesting2() { function nested() { @@ -274,7 +275,7 @@ describe('S1541', () => { } } `), - invalid(` + invalid(` class C { ko() { //P^^ @@ -288,7 +289,7 @@ describe('S1541', () => { } } `), - invalid(` + invalid(` class D { nesting() { function nested() { @@ -302,7 +303,7 @@ describe('S1541', () => { } } `), - invalid(` + invalid(` function ko() { return { get x() { @@ -320,7 +321,7 @@ describe('S1541', () => { }; } `), - invalid(` + invalid(` function ok() { if (a) {} throw "error"; @@ -337,8 +338,8 @@ describe('S1541', () => { }; } `), - invalid( - ` + invalid( + ` export function toCreateModule() {} function complexFunction() { @@ -375,88 +376,91 @@ describe('S1541', () => { return 32; } `, - 10, - ), - ], - }); + 10, + ), + ], + }); - function invalid(code: string, threshold = 2) { - const issue = { - complexity: 0, - primaryLocation: {} as IssueLocation, - secondaryLocations: [] as IssueLocation[], - }; - const lines = code.split('\n'); - for (const [index, line] of lines.entries()) { - let found: RegExpMatchArray | null; + function invalid(code: string, threshold = 2) { + const issue = { + complexity: 0, + primaryLocation: {} as IssueLocation, + secondaryLocations: [] as IssueLocation[], + }; + const lines = code.split('\n'); + for (const [index, line] of lines.entries()) { + let found: RegExpMatchArray | null; - const primary = /\/\/P\s*(\^+)/; - found = line.match(primary); - if (found) { - const marker = found[1]; - const column = line.indexOf(marker); - issue.primaryLocation = location(index, column, index, column + marker.length); - } + const primary = /\/\/P\s*(\^+)/; + found = line.match(primary); + if (found) { + const marker = found[1]; + const column = line.indexOf(marker); + issue.primaryLocation = location(index, column, index, column + marker.length); + } - const secondary = /\/\/\s*[^\^]*(\^+)/; - found = line.match(secondary); - if (found) { - const marker = found[1]; - const column = line.indexOf(marker); - issue.complexity += 1; - issue.secondaryLocations.push(location(index, column, index, column + marker.length, '+1')); + const secondary = /\/\/\s*[^\^]*(\^+)/; + found = line.match(secondary); + if (found) { + const marker = found[1]; + const column = line.indexOf(marker); + issue.complexity += 1; + issue.secondaryLocations.push( + location(index, column, index, column + marker.length, '+1'), + ); + } } - } - return { - code, - errors: [error(issue, threshold)], - options: [ - { - threshold, - }, - ], - }; - } + return { + code, + errors: [error(issue, threshold)], + options: [ + { + threshold, + }, + ], + }; + } - function error( - issue: { - complexity: number; - primaryLocation: IssueLocation; - secondaryLocations: IssueLocation[]; - }, - threshold: number, - ) { - const { line, column, endLine, endColumn } = issue.primaryLocation; - return { - message: encode(issue.complexity, threshold, issue.secondaryLocations), - line, - column: column + 1, - endColumn: endColumn + 1, - endLine, - }; - } + function error( + issue: { + complexity: number; + primaryLocation: IssueLocation; + secondaryLocations: IssueLocation[]; + }, + threshold: number, + ) { + const { line, column, endLine, endColumn } = issue.primaryLocation; + return { + message: encode(issue.complexity, threshold, issue.secondaryLocations), + line, + column: column + 1, + endColumn: endColumn + 1, + endLine, + }; + } - function encode( - complexity: number, - threshold: number, - secondaryLocations: IssueLocation[], - ): string { - const encodedMessage: EncodedMessage = { - message: `Function has a complexity of ${complexity} which is greater than ${threshold} authorized.`, - cost: complexity - threshold, - secondaryLocations, - }; - return JSON.stringify(encodedMessage); - } + function encode( + complexity: number, + threshold: number, + secondaryLocations: IssueLocation[], + ): string { + const encodedMessage: EncodedMessage = { + message: `Function has a complexity of ${complexity} which is greater than ${threshold} authorized.`, + cost: complexity - threshold, + secondaryLocations, + }; + return JSON.stringify(encodedMessage); + } - function location( - line: number, - column: number, - endLine: number, - endColumn: number, - message?: string, - ): IssueLocation { - return { line, column, endLine, endColumn, message }; - } + function location( + line: number, + column: number, + endLine: number, + endColumn: number, + message?: string, + ): IssueLocation { + return { line, column, endLine, endColumn, message }; + } + }); }); diff --git a/packages/jsts/src/rules/S1607/unit.test.ts b/packages/jsts/src/rules/S1607/unit.test.ts index 0444979e76..22fa46a252 100644 --- a/packages/jsts/src/rules/S1607/unit.test.ts +++ b/packages/jsts/src/rules/S1607/unit.test.ts @@ -16,18 +16,20 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1607', () => { - process.chdir(import.meta.dirname); // change current working dir to avoid the package.json lookup to up in the tree - const ruleTester = new RuleTester(); + it('S1607', () => { + process.chdir(import.meta.dirname); // change current working dir to avoid the package.json lookup to up in the tree + const ruleTester = new RuleTester(); - ruleTester.run(`Tests should not be skipped without providing a reason`, rule, { - valid: [ - { - code: `it.skip('test', function() {});`, - }, - ], - invalid: [], + ruleTester.run(`Tests should not be skipped without providing a reason`, rule, { + valid: [ + { + code: `it.skip('test', function() {});`, + }, + ], + invalid: [], + }); }); }); diff --git a/packages/jsts/src/rules/S1751/unit.test.ts b/packages/jsts/src/rules/S1751/unit.test.ts index 15cd716ba9..21b94ff8a9 100644 --- a/packages/jsts/src/rules/S1751/unit.test.ts +++ b/packages/jsts/src/rules/S1751/unit.test.ts @@ -16,19 +16,20 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1751', () => { - const ruleTester = new RuleTester(); + it('S1751', () => { + const ruleTester = new RuleTester(); - ruleTester.run('no-one-iteration-loop', rule, { - valid: [ - valid(` + ruleTester.run('no-one-iteration-loop', rule, { + valid: [ + valid(` while (cond) { 1; }`), - valid(` + valid(` while(foo()) { bar(); if (baz()) { @@ -36,7 +37,7 @@ describe('S1751', () => { } }`), - valid(` + valid(` while(foo()) { switch (bar()) { case a : continue; @@ -45,24 +46,24 @@ describe('S1751', () => { } }`), - valid(` + valid(` function foo() { for(x of arr) { doSomething(() => { return "bar";}); } }`), - valid(` + valid(` while (42) continue `), - valid(` + valid(` for (;42;) continue `), - valid(` + valid(` function foo() { while (42) { continue @@ -73,32 +74,32 @@ describe('S1751', () => { } `), - valid(` + valid(` do { continue } while (42); `), - valid(` + valid(` for (p in obj) { foo(); continue; }`), - valid(` + valid(` function foo() { for(p of arr) { return p; // Compliant: used to return the first element of an array } }`), - valid(` + valid(` for (p in obj) { bar(); break; // Compliant: often used to check whether an object is "empty" }`), - valid(` + valid(` while(foo()) { if (bar()) { continue; @@ -107,7 +108,7 @@ describe('S1751', () => { break; // Compliant: the loop can execute more than once }`), - valid(` + valid(` do { if(bar()) { continue; @@ -116,7 +117,7 @@ describe('S1751', () => { break; // Compliant: the loop can execture more than once } while (foo())`), - valid(` + valid(` while(foo()) { if (bar()) { continue; @@ -125,7 +126,7 @@ describe('S1751', () => { continue; }`), - valid(` + valid(` for (let i = 0; foo(); i++) { if (bar()) { continue; @@ -133,13 +134,13 @@ describe('S1751', () => { baz(); break; // Compliant }`), - valid(` + valid(` for (i = 0; foo(); i++) { baz(); continue; }`), - valid(` + valid(` function foo(){ for (;;) { if (condition) { @@ -150,7 +151,7 @@ describe('S1751', () => { } }`), - valid(` + valid(` function tryCatch() { while (cond()) { try { @@ -163,7 +164,7 @@ describe('S1751', () => { } }`), - valid(` + valid(` function fun() { while(foo()) { bar(); @@ -172,32 +173,32 @@ describe('S1751', () => { } } }`), - ], + ], - invalid: [ - invalid(` + invalid: [ + invalid(` while (cond) { break; }`), - invalid(` + invalid(` while(foo()) { bar(); break; }`), - invalid(` + invalid(` while(foo()) { bar(); throw x; }`), - invalid(` + invalid(` while(foo()) break; `), - invalid(` + invalid(` function f() { while(foo()) { bar(); @@ -205,19 +206,19 @@ describe('S1751', () => { } }`), - invalid(` + invalid(` do { bar(); break; } while (foo())`), - invalid(` + invalid(` for (i = 0; foo(); i++) { bar(); break; }`), - invalid(` + invalid(` for (p in obj) { while(true) { bar(); @@ -225,7 +226,7 @@ describe('S1751', () => { } }`), - invalid(` + invalid(` while(foo()) { if (bar()) { break; @@ -234,20 +235,20 @@ describe('S1751', () => { break; }`), - invalid(` + invalid(` if (cond()) { while(foo()) { break; } }`), - invalid(` + invalid(` for (i = 0; foo();) { baz(); break; }`), - invalid(` + invalid(` function foo() { for (;;) { foo(); @@ -255,7 +256,7 @@ describe('S1751', () => { } }`), - invalid(` + invalid(` while (foo()) { if (bar()) { doSomething(); @@ -266,7 +267,7 @@ describe('S1751', () => { } }`), - invalid(` + invalid(` function twoReturns() { while (foo()) { if (bar()) { @@ -276,23 +277,24 @@ describe('S1751', () => { } } }`), - ], - }); - - function invalid(code: string) { - return { - code, - errors: [ - { - messageId: 'refactorLoop', - }, ], - }; - } - - function valid(code: string) { - return { - code, - }; - } + }); + + function invalid(code: string) { + return { + code, + errors: [ + { + messageId: 'refactorLoop', + }, + ], + }; + } + + function valid(code: string) { + return { + code, + }; + } + }); }); diff --git a/packages/jsts/src/rules/S1763/unit.test.ts b/packages/jsts/src/rules/S1763/unit.test.ts index 9e1ff1f691..b1e33098d4 100644 --- a/packages/jsts/src/rules/S1763/unit.test.ts +++ b/packages/jsts/src/rules/S1763/unit.test.ts @@ -16,48 +16,49 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1763', () => { - const ruleTester = new RuleTester(); + it('S1763', () => { + const ruleTester = new RuleTester(); - ruleTester.run(`Decorated rule should provide suggestion`, rule, { - valid: [ - { - code: ` + ruleTester.run(`Decorated rule should provide suggestion`, rule, { + valid: [ + { + code: ` while (a()) { b(); break; } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` while (a()) { break; b(); } `, - errors: [ - { - messageId: 'unreachableCode', - suggestions: [ - { - output: ` + errors: [ + { + messageId: 'unreachableCode', + suggestions: [ + { + output: ` while (a()) { break; } `, - desc: 'Remove unreachable code', - }, - ], - }, - ], - }, - { - code: ` + desc: 'Remove unreachable code', + }, + ], + }, + ], + }, + { + code: ` while (a()) { b(); break; @@ -65,23 +66,24 @@ while (a()) { d(); } `, - errors: [ - { - messageId: 'unreachableCode', - suggestions: [ - { - output: ` + errors: [ + { + messageId: 'unreachableCode', + suggestions: [ + { + output: ` while (a()) { b(); break; } `, - desc: 'Remove unreachable code', - }, - ], - }, - ], - }, - ], + desc: 'Remove unreachable code', + }, + ], + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1764/unit.test.ts b/packages/jsts/src/rules/S1764/unit.test.ts index 3662f891f4..2ae9282a2b 100644 --- a/packages/jsts/src/rules/S1764/unit.test.ts +++ b/packages/jsts/src/rules/S1764/unit.test.ts @@ -16,247 +16,249 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1764', () => { - const ruleTester = new RuleTester(); + it('S1764', () => { + const ruleTester = new RuleTester(); - ruleTester.run('no-identical-expressions', rule, { - valid: [ - { code: `1 << 1;` }, - { code: `1n << 1n;` }, - { code: `foo(), foo();` }, - { code: `if (Foo instanceof Foo) { }` }, - { - code: `name === "any" || name === "string" || name === "number" || name === "boolean" || name === "never"`, - }, - { code: `a != a;` }, - { code: `a === a;` }, - { code: `a !== a;` }, + ruleTester.run('no-identical-expressions', rule, { + valid: [ + { code: `1 << 1;` }, + { code: `1n << 1n;` }, + { code: `foo(), foo();` }, + { code: `if (Foo instanceof Foo) { }` }, + { + code: `name === "any" || name === "string" || name === "number" || name === "boolean" || name === "never"`, + }, + { code: `a != a;` }, + { code: `a === a;` }, + { code: `a !== a;` }, - { code: `node.text === "eval" || node.text === "arguments";` }, - { code: `nodeText === '"use strict"' || nodeText === "'use strict'";` }, - { - code: `name.charCodeAt(0) === CharacterCodes._ && name.charCodeAt(1) === CharacterCodes._;`, - }, - { code: `if (+a !== +b) { }` }, - { code: 'first(`const`) || first(`var`);' }, - { - code: 'window[`${prefix}CancelAnimationFra me`] || window[`${prefix}CancelRequestAnimationFrame`];', - }, - { code: '' }, - { code: `dirPath.match(/localhost:\d+/) || dirPath.match(/localhost:\d+\s/);` }, - { code: `a == b || a == c;` }, - { code: `a == b;` }, - ], - invalid: [ - { - code: 'a == b && a == b', - errors: [ - { - messageId: 'correctIdenticalSubExpressions', - data: { - operator: '&&', + { code: `node.text === "eval" || node.text === "arguments";` }, + { code: `nodeText === '"use strict"' || nodeText === "'use strict'";` }, + { + code: `name.charCodeAt(0) === CharacterCodes._ && name.charCodeAt(1) === CharacterCodes._;`, + }, + { code: `if (+a !== +b) { }` }, + { code: 'first(`const`) || first(`var`);' }, + { + code: 'window[`${prefix}CancelAnimationFra me`] || window[`${prefix}CancelRequestAnimationFrame`];', + }, + { code: '' }, + { code: `dirPath.match(/localhost:\d+/) || dirPath.match(/localhost:\d+\s/);` }, + { code: `a == b || a == c;` }, + { code: `a == b;` }, + ], + invalid: [ + { + code: 'a == b && a == b', + errors: [ + { + messageId: 'correctIdenticalSubExpressions', + data: { + operator: '&&', + }, + column: 1, + endColumn: 17, }, - column: 1, - endColumn: 17, - }, - ], - }, - { - code: 'a == b || a == b', - errors: [ - { - messageId: 'correctIdenticalSubExpressions', - data: { - operator: '||', + ], + }, + { + code: 'a == b || a == b', + errors: [ + { + messageId: 'correctIdenticalSubExpressions', + data: { + operator: '||', + }, }, - }, - ], - }, - { - code: `a == b || a == b + ], + }, + { + code: `a == b || a == b // ^^^^^^> ^^^^^^`, - options: ['sonar-runtime'], - errors: [ - { - messageId: 'sonarRuntime', - data: { - operator: '||', - sonarRuntimeData: JSON.stringify({ - message: - 'Correct one of the identical sub-expressions on both sides of operator "||"', - secondaryLocations: [ - { - column: 0, - line: 1, - endColumn: 6, - endLine: 1, - }, - ], - }), + options: ['sonar-runtime'], + errors: [ + { + messageId: 'sonarRuntime', + data: { + operator: '||', + sonarRuntimeData: JSON.stringify({ + message: + 'Correct one of the identical sub-expressions on both sides of operator "||"', + secondaryLocations: [ + { + column: 0, + line: 1, + endColumn: 6, + endLine: 1, + }, + ], + }), + }, + line: 1, + endLine: 1, + column: 11, + endColumn: 17, }, - line: 1, - endLine: 1, - column: 11, - endColumn: 17, - }, - ], - }, - { - code: 'a > a', - errors: [ - { - messageId: 'correctIdenticalSubExpressions', - data: { - operator: '>', + ], + }, + { + code: 'a > a', + errors: [ + { + messageId: 'correctIdenticalSubExpressions', + data: { + operator: '>', + }, }, - }, - ], - }, - { - code: 'a >= a', - errors: [ - { - messageId: 'correctIdenticalSubExpressions', - data: { - operator: '>=', + ], + }, + { + code: 'a >= a', + errors: [ + { + messageId: 'correctIdenticalSubExpressions', + data: { + operator: '>=', + }, }, - }, - ], - }, - { - code: 'a < a', - errors: [ - { - messageId: 'correctIdenticalSubExpressions', - data: { - operator: '<', + ], + }, + { + code: 'a < a', + errors: [ + { + messageId: 'correctIdenticalSubExpressions', + data: { + operator: '<', + }, }, - }, - ], - }, - { - code: 'a <= a', - errors: [ - { - messageId: 'correctIdenticalSubExpressions', - data: { - operator: '<=', + ], + }, + { + code: 'a <= a', + errors: [ + { + messageId: 'correctIdenticalSubExpressions', + data: { + operator: '<=', + }, }, - }, - ], - }, - { - code: '5 / 5', - errors: [ - { - messageId: 'correctIdenticalSubExpressions', - data: { - operator: '/', + ], + }, + { + code: '5 / 5', + errors: [ + { + messageId: 'correctIdenticalSubExpressions', + data: { + operator: '/', + }, }, - }, - ], - }, - { - code: '5 - 5', - errors: [ - { - messageId: 'correctIdenticalSubExpressions', - data: { - operator: '-', + ], + }, + { + code: '5 - 5', + errors: [ + { + messageId: 'correctIdenticalSubExpressions', + data: { + operator: '-', + }, }, - }, - ], - }, - { - code: 'a << a', - errors: [ - { - messageId: 'correctIdenticalSubExpressions', - data: { - operator: '<<', + ], + }, + { + code: 'a << a', + errors: [ + { + messageId: 'correctIdenticalSubExpressions', + data: { + operator: '<<', + }, }, - }, - ], - }, - { - code: 'a >> a', - errors: [ - { - messageId: 'correctIdenticalSubExpressions', - data: { - operator: '>>', + ], + }, + { + code: 'a >> a', + errors: [ + { + messageId: 'correctIdenticalSubExpressions', + data: { + operator: '>>', + }, }, - }, - ], - }, - { - code: '1 >> 1', - errors: [ - { - messageId: 'correctIdenticalSubExpressions', - data: { - operator: '>>', + ], + }, + { + code: '1 >> 1', + errors: [ + { + messageId: 'correctIdenticalSubExpressions', + data: { + operator: '>>', + }, }, - }, - ], - }, - { - code: '5 << 5', - errors: [ - { - messageId: 'correctIdenticalSubExpressions', - data: { - operator: '<<', + ], + }, + { + code: '5 << 5', + errors: [ + { + messageId: 'correctIdenticalSubExpressions', + data: { + operator: '<<', + }, }, - }, - ], - }, - { - code: 'obj.foo() == obj.foo()', - errors: [ - { - messageId: 'correctIdenticalSubExpressions', - data: { - operator: '==', + ], + }, + { + code: 'obj.foo() == obj.foo()', + errors: [ + { + messageId: 'correctIdenticalSubExpressions', + data: { + operator: '==', + }, }, - }, - ], - }, - { - code: 'foo(/*comment*/() => doSomething()) === foo(() => doSomething())', - errors: [ - { - messageId: 'correctIdenticalSubExpressions', - data: { - operator: '===', + ], + }, + { + code: 'foo(/*comment*/() => doSomething()) === foo(() => doSomething())', + errors: [ + { + messageId: 'correctIdenticalSubExpressions', + data: { + operator: '===', + }, }, - }, - ], - }, - { - code: '(a == b) == (a == b)', - errors: [ - { - messageId: 'correctIdenticalSubExpressions', - data: { - operator: '==', + ], + }, + { + code: '(a == b) == (a == b)', + errors: [ + { + messageId: 'correctIdenticalSubExpressions', + data: { + operator: '==', + }, }, - }, - ], - }, - { - code: 'if (+a !== +a);', - errors: [ - { - messageId: 'correctIdenticalSubExpressions', - data: { - operator: '!==', + ], + }, + { + code: 'if (+a !== +a);', + errors: [ + { + messageId: 'correctIdenticalSubExpressions', + data: { + operator: '!==', + }, }, - }, - ], - }, - ], + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1821/unit.test.ts b/packages/jsts/src/rules/S1821/unit.test.ts index 95e1289259..47abf9f64a 100644 --- a/packages/jsts/src/rules/S1821/unit.test.ts +++ b/packages/jsts/src/rules/S1821/unit.test.ts @@ -16,25 +16,26 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1821', () => { - const ruleTester = new RuleTester(); + it('S1821', () => { + const ruleTester = new RuleTester(); - const messageId = 'removeNestedSwitch'; + const messageId = 'removeNestedSwitch'; - ruleTester.run('switch statements should not be nested', rule, { - valid: [ - { - code: `switch (x) { + ruleTester.run('switch statements should not be nested', rule, { + valid: [ + { + code: `switch (x) { case 1: a; break; default: b; };`, - }, - ], - invalid: [ - { - code: `switch (x) { + }, + ], + invalid: [ + { + code: `switch (x) { case 1: a; break; case 2: switch (y) { @@ -44,18 +45,18 @@ describe('S1821', () => { break; default: b; }`, - errors: [ - { - messageId, - line: 4, - endLine: 4, - column: 11, - endColumn: 17, - }, - ], - }, - { - code: `switch (x) { + errors: [ + { + messageId, + line: 4, + endLine: 4, + column: 11, + endColumn: 17, + }, + ], + }, + { + code: `switch (x) { case 1: a; break; case 2: { switch (y) { @@ -70,25 +71,25 @@ describe('S1821', () => { } default: b; }`, - errors: [ - { - messageId, - line: 4, - endLine: 4, - column: 15, - endColumn: 21, - }, - { - messageId, - line: 8, - endLine: 8, - column: 15, - endColumn: 21, - }, - ], - }, - { - code: `switch (x) { + errors: [ + { + messageId, + line: 4, + endLine: 4, + column: 15, + endColumn: 21, + }, + { + messageId, + line: 8, + endLine: 8, + column: 15, + endColumn: 21, + }, + ], + }, + { + code: `switch (x) { case 1: a; break; case 2: switch (y) { @@ -102,25 +103,25 @@ describe('S1821', () => { break; default: b; }`, - errors: [ - { - messageId, - line: 4, - endLine: 4, - column: 15, - endColumn: 21, - }, - { - messageId, - line: 7, - endLine: 7, - column: 19, - endColumn: 25, - }, - ], - }, - { - code: `switch (x) { + errors: [ + { + messageId, + line: 4, + endLine: 4, + column: 15, + endColumn: 21, + }, + { + messageId, + line: 7, + endLine: 7, + column: 19, + endColumn: 25, + }, + ], + }, + { + code: `switch (x) { case 1: a; case 2: b; default: @@ -129,33 +130,34 @@ describe('S1821', () => { default: d; } }`, - errors: [ - { - messageId, - line: 5, - endLine: 5, - column: 15, - endColumn: 21, - }, - ], - }, - { - code: `switch (x) { + errors: [ + { + messageId, + line: 5, + endLine: 5, + column: 15, + endColumn: 21, + }, + ], + }, + { + code: `switch (x) { case 1: let isideFunction = () => { switch (y) {} } }`, - errors: [ - { - messageId, - line: 4, - endLine: 4, - column: 17, - endColumn: 23, - }, - ], - }, - ], + errors: [ + { + messageId, + line: 4, + endLine: 4, + column: 17, + endColumn: 23, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1848/unit.test.ts b/packages/jsts/src/rules/S1848/unit.test.ts index 0e1336d1b2..8dd770a351 100644 --- a/packages/jsts/src/rules/S1848/unit.test.ts +++ b/packages/jsts/src/rules/S1848/unit.test.ts @@ -16,66 +16,67 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1848', () => { - const ruleTester = new RuleTester(); + it('S1848', () => { + const ruleTester = new RuleTester(); - ruleTester.run( - `Objects should not be created to be dropped immediately without being used`, - rule, - { - valid: [ - { - code: ` + ruleTester.run( + `Objects should not be created to be dropped immediately without being used`, + rule, + { + valid: [ + { + code: ` export default new MyConstructor(); // OK var something = new MyConstructor(); // OK something = new MyConstructor(); // OK callMethod(new MyConstructor()); // OK new MyConstructor().doSomething(); // OK `, - }, - { - code: ` + }, + { + code: ` try { new MyConstructor(); } catch (e) {} try { if (cond()) { new MyConstructor(); } } catch (e) {} `, - }, - { - code: `new MyConstructor();`, - settings: { fileType: 'TEST' }, - }, - { - code: ` + }, + { + code: `new MyConstructor();`, + settings: { fileType: 'TEST' }, + }, + { + code: ` new Notification("hello there"); `, - }, - { - code: ` + }, + { + code: ` import Vue from 'vue'; new Vue(); `, - }, - { - code: ` + }, + { + code: ` const SomeAlias = require('vue'); new SomeAlias(); `, - }, - { - code: ` + }, + { + code: ` import { Grid } from '@ag-grid-community/core'; new Grid(); `, - }, - { - code: ` + }, + { + code: ` const { Grid } = require('@ag-grid-community/core'); new Grid(); `, - }, - { - code: ` + }, + { + code: ` import * as s3 from 'aws-cdk-lib/aws-s3'; export class Stack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { @@ -84,68 +85,69 @@ export class Stack extends cdk.Stack { new s3.Bucket(this, 'TempBucket', {}); } }`, - }, - ], - invalid: [ - { - code: `new MyConstructor(); + }, + ], + invalid: [ + { + code: `new MyConstructor(); new c.MyConstructor(123);`, - errors: [ - { - message: `Either remove this useless object instantiation of "MyConstructor" or use it.`, - line: 1, - column: 1, - endLine: 1, - endColumn: 18, - }, - { - message: `Either remove this useless object instantiation of "c.MyConstructor" or use it.`, - line: 2, - column: 14, - endLine: 2, - endColumn: 33, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Either remove this useless object instantiation of "MyConstructor" or use it.`, + line: 1, + column: 1, + endLine: 1, + endColumn: 18, + }, + { + message: `Either remove this useless object instantiation of "c.MyConstructor" or use it.`, + line: 2, + column: 14, + endLine: 2, + endColumn: 33, + }, + ], + }, + { + code: ` new function() { //... // A lot of code... }`, - errors: [ - { - message: `Either remove this useless object instantiation or use it.`, - line: 2, - column: 7, - endLine: 2, - endColumn: 10, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Either remove this useless object instantiation or use it.`, + line: 2, + column: 7, + endLine: 2, + endColumn: 10, + }, + ], + }, + { + code: ` try {} catch (e) { new MyConstructor(); } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` import Vue from 'not-vue'; import { Grid } from 'not-ag-grid'; new Vue(); new Grid(); `, - errors: 2, - }, - { - code: ` + errors: 2, + }, + { + code: ` import Grid from '@ag-grid-community/core'; new Grid(); `, - errors: 1, - }, - ], - }, - ); + errors: 1, + }, + ], + }, + ); + }); }); diff --git a/packages/jsts/src/rules/S1854/unit.test.ts b/packages/jsts/src/rules/S1854/unit.test.ts index cb1d2c87dc..bf291afacc 100644 --- a/packages/jsts/src/rules/S1854/unit.test.ts +++ b/packages/jsts/src/rules/S1854/unit.test.ts @@ -16,15 +16,16 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTester = new RuleTester(); describe('S1854', () => { - ruleTester.run('Dead stores should be removed', rule, { - valid: [ - { - code: ` + it('S1854', () => { + ruleTester.run('Dead stores should be removed', rule, { + valid: [ + { + code: ` function foo(cond) { let x = 1; if (cond) { @@ -32,23 +33,23 @@ describe('S1854', () => { } } `, - }, - { - code: ` + }, + { + code: ` var global1 = 42; `, - }, - { - code: `const {run} = Ember;`, - }, - { - code: ` + }, + { + code: `const {run} = Ember;`, + }, + { + code: ` function functionParameter(p) { // OK } `, - }, - { - code: ` + }, + { + code: ` function write_in_nested_function_expression() { var a = 42; executeConditionally(function() { @@ -57,9 +58,9 @@ describe('S1854', () => { return a; } `, - }, - { - code: ` + }, + { + code: ` function read_in_nested_function_expression() { var a = 42; var f = function() { @@ -68,9 +69,9 @@ describe('S1854', () => { a = 1; // OK return f; }`, - }, - { - code: ` + }, + { + code: ` function read_in_nested_function_declaration() { var a = 42; function f() { @@ -79,9 +80,9 @@ describe('S1854', () => { a = 1; // OK return f; }`, - }, - { - code: ` + }, + { + code: ` function read_in_nested_method() { var a = 42; class A { @@ -92,33 +93,33 @@ describe('S1854', () => { a = 1; // OK return new A(); }`, - }, - { - code: ` + }, + { + code: ` function blockless_arrow_function() { doSomething(() => 1); } `, - }, - { - code: ` + }, + { + code: ` function assignment_order() { var x = foo(); // OK x = bar(x); return baz(x); } `, - }, - { - code: ` + }, + { + code: ` var globalCounter = 0; function getUniqueId() { return ++globalCounter; } `, - }, - { - code: ` + }, + { + code: ` var x = function loops() { let i = 0; let length; @@ -126,11 +127,11 @@ describe('S1854', () => { } } `, - }, - { - // this test case demonstrates that unreachable elements will not be part of any CodePathSegment - // see https://eslint.org/docs/developer-guide/code-path-analysis#forstatement-for-ever - code: ` + }, + { + // this test case demonstrates that unreachable elements will not be part of any CodePathSegment + // see https://eslint.org/docs/developer-guide/code-path-analysis#forstatement-for-ever + code: ` function forever() { for (;; ) { @@ -138,15 +139,15 @@ describe('S1854', () => { foo(); } `, - }, - { - code: ` + }, + { + code: ` let x = 1; x = foo() ? x : 2; `, - }, - { - code: ` + }, + { + code: ` function f(){ const mod = "foo"; switch (mod) { @@ -157,15 +158,15 @@ describe('S1854', () => { } } `, - }, - { - code: ` function f(){ + }, + { + code: ` function f(){ let {x} = bar(); foo(x); }`, - }, - { - code: ` + }, + { + code: ` function foo(map) { let i; for (const _ in map) { @@ -173,17 +174,17 @@ describe('S1854', () => { } } `, - }, - { - code: ` + }, + { + code: ` function f(a,b) { var d = (d = a - b) * d + (d = a - b) * d; foo(d); } `, - }, - { - code: ` + }, + { + code: ` function f() { let {a, ...rest} = foo(); bar(rest); @@ -193,55 +194,55 @@ describe('S1854', () => { bar(rest); } `, - }, - { - code: ` + }, + { + code: ` var x; function foo() { x = 5; }`, - }, - { - code: ` + }, + { + code: ` function read_write() { var i = 42; var j = i++; doSomething(j); }`, - }, - { - code: ` + }, + { + code: ` function foo() { let x = 42; console.log(x); x = null; } `, - }, - { - code: ` + }, + { + code: ` const enum A { Monday = 1, Tuesday = 2 } `, - }, - { - code: ` + }, + { + code: ` class A { constructor(private concurrent: number = 42) { } } `, - }, - { - code: ` + }, + { + code: ` namespace ts { export const version = "2.4.0"; } `, - }, - { - code: ` + }, + { + code: ` function getIconSettings() { const Container = styled.div\` width: 26px; @@ -253,11 +254,11 @@ describe('S1854', () => { ) } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function foo(cond) { let x = 1; if (cond) { @@ -265,17 +266,17 @@ describe('S1854', () => { } } `, - errors: [ - { - message: 'Remove this useless assignment to variable "x".', - line: 5, - endLine: 5, - column: 9, - endColumn: 10, - }, - ], - }, - noncompliant(` + errors: [ + { + message: 'Remove this useless assignment to variable "x".', + line: 5, + endLine: 5, + column: 9, + endColumn: 10, + }, + ], + }, + noncompliant(` function foo(condition, a) { var x; x = 42; // Noncompliant @@ -287,7 +288,7 @@ describe('S1854', () => { foo(x); } `), - noncompliant(` + noncompliant(` function loops() { var i = 42; while(i < 10) { @@ -300,7 +301,7 @@ describe('S1854', () => { j = k + 1; // Noncompliant } }`), - noncompliant(` + noncompliant(` function write_in_nested_function_expression_but_never_read() { var a = 42; // Noncompliant execute(function() { @@ -308,7 +309,7 @@ describe('S1854', () => { }); } `), - noncompliant(` + noncompliant(` function arrow_function() { doSomething(() => { var x = 42; // Noncompliant @@ -316,21 +317,21 @@ describe('S1854', () => { return x; }); }`), - noncompliant(` + noncompliant(` class A { method1() { var x = 42; // Noncompliant return y; } }`), - noncompliant(` + noncompliant(` function let_variable() { if (condition()) { let x = 42; // Noncompliant } } `), - noncompliant(` + noncompliant(` // -1, 0, 1, null, true, false, "" and void 0. function ok_initializer_to_standard_value() { let [a, b] = [42, 1]; // Noncompliant @@ -387,7 +388,7 @@ describe('S1854', () => { } `), - noncompliant(` + noncompliant(` function getIconSettings() { const Container = styled.div\` width: 26px; @@ -400,7 +401,7 @@ describe('S1854', () => { ) } `), - noncompliant(` + noncompliant(` function f() { let {a, b} = foo(); // Noncompliant bar(a); @@ -409,28 +410,29 @@ describe('S1854', () => { bar(x); } `), - noncompliant(` + noncompliant(` function f() { // 'b' is ignored but 'unused' is reported let {unused, a: {b, ...rest}} = foo(); // Noncompliant foo(rest); } `), - ], + ], + }); }); -}); -function noncompliant(code: string) { - const nonCompliantLines: number[] = []; - code.split('\n').forEach((line, idx) => { - if (line.includes('// Noncompliant')) { - nonCompliantLines.push(idx + 1); - } - }); - return { - code, - errors: nonCompliantLines.map(l => { - return { messageId: 'removeAssignment', line: l }; - }), - }; -} + function noncompliant(code: string) { + const nonCompliantLines: number[] = []; + code.split('\n').forEach((line, idx) => { + if (line.includes('// Noncompliant')) { + nonCompliantLines.push(idx + 1); + } + }); + return { + code, + errors: nonCompliantLines.map(l => { + return { messageId: 'removeAssignment', line: l }; + }), + }; + } +}); diff --git a/packages/jsts/src/rules/S1862/unit.test.ts b/packages/jsts/src/rules/S1862/unit.test.ts index 23006ce0e4..cf5fc7ad2c 100644 --- a/packages/jsts/src/rules/S1862/unit.test.ts +++ b/packages/jsts/src/rules/S1862/unit.test.ts @@ -16,35 +16,36 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1862', () => { - const ruleTester = new RuleTester(); + it('S1862', () => { + const ruleTester = new RuleTester(); - const SONAR_RUNTIME = 'sonar-runtime'; + const SONAR_RUNTIME = 'sonar-runtime'; - ruleTester.run('no-identical-conditions', rule, { - valid: [ - { - code: 'if (a) {} else if (b) {}', - }, - { - code: 'if (a) {} else {}', - }, - { - code: 'if (a && b) {} else if (a) {}', - }, - { - code: 'if (a && b) {} else if (c && d) {}', - }, - { - code: 'if (a || b) {} else if (c || d) {}', - }, - { - code: 'if (a ?? b) {} else if (c) {}', - }, - { - code: ` + ruleTester.run('no-identical-conditions', rule, { + valid: [ + { + code: 'if (a) {} else if (b) {}', + }, + { + code: 'if (a) {} else {}', + }, + { + code: 'if (a && b) {} else if (a) {}', + }, + { + code: 'if (a && b) {} else if (c && d) {}', + }, + { + code: 'if (a || b) {} else if (c || d) {}', + }, + { + code: 'if (a ?? b) {} else if (c) {}', + }, + { + code: ` switch (a) { case 1: break; case 2: break; @@ -52,213 +53,213 @@ describe('S1862', () => { default: break; } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` if (a) {} else if (a) {} `, - errors: [ - { - messageId: 'duplicatedCondition', - data: { - line: 2, + errors: [ + { + messageId: 'duplicatedCondition', + data: { + line: 2, + }, + line: 3, + column: 18, + endColumn: 19, }, - line: 3, - column: 18, - endColumn: 19, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` if (a) {} // ^> else if (a) {} // ^ `, - options: [SONAR_RUNTIME], - errors: [ - { - messageId: 'sonarRuntime', - data: { - line: 2, - sonarRuntimeData: JSON.stringify({ - message: 'This condition is covered by the one on line 2', - secondaryLocations: [ - { - message: 'Covering', - column: 12, - line: 2, - endColumn: 13, - endLine: 2, - }, - ], - }), + options: [SONAR_RUNTIME], + errors: [ + { + messageId: 'sonarRuntime', + data: { + line: 2, + sonarRuntimeData: JSON.stringify({ + message: 'This condition is covered by the one on line 2', + secondaryLocations: [ + { + message: 'Covering', + column: 12, + line: 2, + endColumn: 13, + endLine: 2, + }, + ], + }), + }, }, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` if (b) {} else if (a) {} else if (a) {} `, - errors: [ - { - messageId: 'duplicatedCondition', - data: { - line: 3, + errors: [ + { + messageId: 'duplicatedCondition', + data: { + line: 3, + }, + line: 4, + column: 18, + endColumn: 19, }, - line: 4, - column: 18, - endColumn: 19, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` if (a) {} else if (b) {} else if (a) {} `, - errors: [ - { - messageId: 'duplicatedCondition', - data: { - line: 2, + errors: [ + { + messageId: 'duplicatedCondition', + data: { + line: 2, + }, + line: 4, + column: 18, + endColumn: 19, }, - line: 4, - column: 18, - endColumn: 19, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` if (a || b) {} // >^^^^^^ else if (a) {} // ^`, - options: [SONAR_RUNTIME], - errors: [ - { - messageId: 'sonarRuntime', - line: 4, - column: 18, - endLine: 4, - endColumn: 19, - data: { - line: 2, - sonarRuntimeData: JSON.stringify({ - message: 'This condition is covered by the one on line 2', - secondaryLocations: [ - { - message: 'Covering', - column: 12, - line: 2, - endColumn: 18, - endLine: 2, - }, - ], - }), + options: [SONAR_RUNTIME], + errors: [ + { + messageId: 'sonarRuntime', + line: 4, + column: 18, + endLine: 4, + endColumn: 19, + data: { + line: 2, + sonarRuntimeData: JSON.stringify({ + message: 'This condition is covered by the one on line 2', + secondaryLocations: [ + { + message: 'Covering', + column: 12, + line: 2, + endColumn: 18, + endLine: 2, + }, + ], + }), + }, }, - }, - ], - }, - { - code: `if (a || b) {} else if (b) {}`, - errors: [{ messageId: 'duplicatedCondition' }], - }, - { - code: `if ((a === b && fn(c)) || d) {} else if (a === b && fn(c)) {}`, - errors: [{ messageId: 'duplicatedCondition' }], - }, - { - code: `if (a) {} else if (a && b) {}`, - errors: [{ messageId: 'duplicatedCondition' }], - }, - { - code: `if (a && b) ; else if (b && a) {}`, - errors: [{ messageId: 'duplicatedCondition' }], - }, - { - code: `if (a) {} else if (b) {} else if (c && a || b) {}`, - errors: [{ messageId: 'duplicatedCondition' }], - }, - { - code: `if (a) {} else if (b) {} else if (c && (a || b)) {}`, - errors: [{ messageId: 'duplicatedCondition' }], - }, - { - code: `if (a) {} else if (b && c) {} else if (d && (a || e && c && b)) {}`, - errors: [{ messageId: 'duplicatedCondition' }], - }, - { - code: `if (a || b && c) {} else if (b && c && d) {}`, - errors: [{ messageId: 'duplicatedCondition' }], - }, - { - code: `if (a || b) {} else if (b && c) {}`, - errors: [{ messageId: 'duplicatedCondition' }], - }, - { - code: `if (a) {} else if (b) {} else if ((a || b) && c) {}`, - errors: [{ messageId: 'duplicatedCondition' }], - }, - { - code: `if ((a && (b || c)) || d) {} else if ((c || b) && e && a) {}`, - errors: [{ messageId: 'duplicatedCondition' }], - }, - { - code: `if (a && b || b && c) {} else if (a && b && c) {}`, - errors: [{ messageId: 'duplicatedCondition' }], - }, - { - code: `if (a) {} else if (b && c) {} else if (d && (c && e && b || a)) {}`, - errors: [{ messageId: 'duplicatedCondition' }], - }, - { - code: `if (a || (b && (c || d))) {} else if ((d || c) && b) {}`, - errors: [{ messageId: 'duplicatedCondition' }], - }, - { - code: `if (a || b) {} else if ((b || a) && c) {}`, - errors: [{ messageId: 'duplicatedCondition' }], - }, - { - code: `if (a || b) {} else if (c) {} else if (d) {} else if (b && (a || c)) {}`, - errors: [{ messageId: 'duplicatedCondition' }], - }, - { - code: `if (a || b || c) {} else if (a || (b && d) || (c && e)) {}`, - errors: [{ messageId: 'duplicatedCondition' }], - }, - { - code: `if (a || (b || c)) {} else if (a || (b && c)) {}`, - errors: [{ messageId: 'duplicatedCondition' }], - }, - { - code: `if (a || b) {} else if (c) {} else if (d) {} else if ((a || c) && (b || d)) {}`, - errors: [{ messageId: 'duplicatedCondition' }], - }, - { - code: `if (a) {} else if (b) {} else if (c && (a || d && b)) {}`, - errors: [{ messageId: 'duplicatedCondition' }], - }, - { - code: `if (a) {} else if (a || a) {}`, - errors: [{ messageId: 'duplicatedCondition' }], - }, - { - code: `if (a) {} else if (a && a) {}`, - errors: [{ messageId: 'duplicatedCondition' }], - }, - { - code: ` + ], + }, + { + code: `if (a || b) {} else if (b) {}`, + errors: [{ messageId: 'duplicatedCondition' }], + }, + { + code: `if ((a === b && fn(c)) || d) {} else if (a === b && fn(c)) {}`, + errors: [{ messageId: 'duplicatedCondition' }], + }, + { + code: `if (a) {} else if (a && b) {}`, + errors: [{ messageId: 'duplicatedCondition' }], + }, + { + code: `if (a && b) ; else if (b && a) {}`, + errors: [{ messageId: 'duplicatedCondition' }], + }, + { + code: `if (a) {} else if (b) {} else if (c && a || b) {}`, + errors: [{ messageId: 'duplicatedCondition' }], + }, + { + code: `if (a) {} else if (b) {} else if (c && (a || b)) {}`, + errors: [{ messageId: 'duplicatedCondition' }], + }, + { + code: `if (a) {} else if (b && c) {} else if (d && (a || e && c && b)) {}`, + errors: [{ messageId: 'duplicatedCondition' }], + }, + { + code: `if (a || b && c) {} else if (b && c && d) {}`, + errors: [{ messageId: 'duplicatedCondition' }], + }, + { + code: `if (a || b) {} else if (b && c) {}`, + errors: [{ messageId: 'duplicatedCondition' }], + }, + { + code: `if (a) {} else if (b) {} else if ((a || b) && c) {}`, + errors: [{ messageId: 'duplicatedCondition' }], + }, + { + code: `if ((a && (b || c)) || d) {} else if ((c || b) && e && a) {}`, + errors: [{ messageId: 'duplicatedCondition' }], + }, + { + code: `if (a && b || b && c) {} else if (a && b && c) {}`, + errors: [{ messageId: 'duplicatedCondition' }], + }, + { + code: `if (a) {} else if (b && c) {} else if (d && (c && e && b || a)) {}`, + errors: [{ messageId: 'duplicatedCondition' }], + }, + { + code: `if (a || (b && (c || d))) {} else if ((d || c) && b) {}`, + errors: [{ messageId: 'duplicatedCondition' }], + }, + { + code: `if (a || b) {} else if ((b || a) && c) {}`, + errors: [{ messageId: 'duplicatedCondition' }], + }, + { + code: `if (a || b) {} else if (c) {} else if (d) {} else if (b && (a || c)) {}`, + errors: [{ messageId: 'duplicatedCondition' }], + }, + { + code: `if (a || b || c) {} else if (a || (b && d) || (c && e)) {}`, + errors: [{ messageId: 'duplicatedCondition' }], + }, + { + code: `if (a || (b || c)) {} else if (a || (b && c)) {}`, + errors: [{ messageId: 'duplicatedCondition' }], + }, + { + code: `if (a || b) {} else if (c) {} else if (d) {} else if ((a || c) && (b || d)) {}`, + errors: [{ messageId: 'duplicatedCondition' }], + }, + { + code: `if (a) {} else if (b) {} else if (c && (a || d && b)) {}`, + errors: [{ messageId: 'duplicatedCondition' }], + }, + { + code: `if (a) {} else if (a || a) {}`, + errors: [{ messageId: 'duplicatedCondition' }], + }, + { + code: `if (a) {} else if (a && a) {}`, + errors: [{ messageId: 'duplicatedCondition' }], + }, + { + code: ` switch (a) { case 1: f(); @@ -271,32 +272,32 @@ describe('S1862', () => { break; } `, - options: [SONAR_RUNTIME], - errors: [ - { - messageId: 'sonarRuntime', - data: { - line: 9, - column: 15, - endColumn: 16, - sonarRuntimeData: JSON.stringify({ - message: 'This case duplicates the one on line 3', - secondaryLocations: [ - { - message: 'Original', - column: 15, - line: 3, - endColumn: 16, - endLine: 3, - }, - ], - }), + options: [SONAR_RUNTIME], + errors: [ + { + messageId: 'sonarRuntime', + data: { + line: 9, + column: 15, + endColumn: 16, + sonarRuntimeData: JSON.stringify({ + message: 'This case duplicates the one on line 3', + secondaryLocations: [ + { + message: 'Original', + column: 15, + line: 3, + endColumn: 16, + endLine: 3, + }, + ], + }), + }, }, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` switch (a) { case 1: f(); @@ -312,27 +313,28 @@ describe('S1862', () => { break; } `, - errors: [ - { - messageId: 'duplicatedCase', - data: { - line: 3, + errors: [ + { + messageId: 'duplicatedCase', + data: { + line: 3, + }, + line: 9, + column: 16, + endColumn: 17, }, - line: 9, - column: 16, - endColumn: 17, - }, - { - messageId: 'duplicatedCase', - data: { - line: 3, + { + messageId: 'duplicatedCase', + data: { + line: 3, + }, + line: 12, + column: 16, + endColumn: 17, }, - line: 12, - column: 16, - endColumn: 17, - }, - ], - }, - ], + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1871/unit.test.ts b/packages/jsts/src/rules/S1871/unit.test.ts index 6716914690..f2958b4fcc 100644 --- a/packages/jsts/src/rules/S1871/unit.test.ts +++ b/packages/jsts/src/rules/S1871/unit.test.ts @@ -16,15 +16,16 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1871', () => { - const ruleTester = new RuleTester(); + it('S1871', () => { + const ruleTester = new RuleTester(); - ruleTester.run('no-duplicated-branches if', rule, { - valid: [ - { - code: ` + ruleTester.run('no-duplicated-branches if', rule, { + valid: [ + { + code: ` if (a) { first('const'); first('foo'); @@ -32,18 +33,18 @@ describe('S1871', () => { first('var'); first('foo'); }`, - }, - { - // small branches - code: ` + }, + { + // small branches + code: ` if (a) { first(); } else { first(); }`, - }, - { - code: ` + }, + { + code: ` if (a) { first(); first(); @@ -51,9 +52,9 @@ describe('S1871', () => { second(); second(); }`, - }, - { - code: ` + }, + { + code: ` if (a) { first(); second(); @@ -61,9 +62,9 @@ describe('S1871', () => { second(); first(); }`, - }, - { - code: ` + }, + { + code: ` if (a) { first(); second(); @@ -71,18 +72,18 @@ describe('S1871', () => { first(); third(); }`, - }, - { - code: ` + }, + { + code: ` if (a) { first(); second(); } else { first(); }`, - }, - { - code: ` + }, + { + code: ` if(a == 1) { doSomething(); //no issue, usually this is done on purpose to increase the readability } else if (a == 2) { @@ -90,11 +91,11 @@ describe('S1871', () => { } else { doSomething(); }`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` if (a) { first(); second(); @@ -102,22 +103,22 @@ describe('S1871', () => { first(); second(); }`, - errors: [ - { - messageId: 'sameConditionalBlock', - data: { - type: 'branch', - line: 2, + errors: [ + { + messageId: 'sameConditionalBlock', + data: { + type: 'branch', + line: 2, + }, + line: 5, + endLine: 8, + column: 14, + endColumn: 8, }, - line: 5, - endLine: 8, - column: 14, - endColumn: 8, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` if (a) { first(); second(); @@ -125,33 +126,33 @@ describe('S1871', () => { first(); second(); }`, - options: ['sonar-runtime'], - errors: [ - { - line: 5, - messageId: 'sonarRuntime', - data: { - type: 'branch', - line: 2, - sonarRuntimeData: JSON.stringify({ - message: - "This branch's code block is the same as the block for the branch on line 2.", - secondaryLocations: [ - { - message: 'Original', - column: 13, - line: 2, - endColumn: 7, - endLine: 5, - }, - ], - }), + options: ['sonar-runtime'], + errors: [ + { + line: 5, + messageId: 'sonarRuntime', + data: { + type: 'branch', + line: 2, + sonarRuntimeData: JSON.stringify({ + message: + "This branch's code block is the same as the block for the branch on line 2.", + secondaryLocations: [ + { + message: 'Original', + column: 13, + line: 2, + endColumn: 7, + endLine: 5, + }, + ], + }), + }, }, - }, - ], - }, + ], + }, - /** + /** * message: JSON.stringify({ secondaryLocations: [ { @@ -166,8 +167,8 @@ describe('S1871', () => { }) */ - { - code: ` + { + code: ` if (a) { first(); second(); @@ -178,37 +179,37 @@ describe('S1871', () => { first(); second(); }`, - errors: [ - { - messageId: 'sameConditionalBlock', - data: { - type: 'branch', - line: 2, + errors: [ + { + messageId: 'sameConditionalBlock', + data: { + type: 'branch', + line: 2, + }, + line: 8, }, - line: 8, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` if(a == 1) { doSomething(); } else if (a == 2) { doSomething(); }`, - errors: [ - { - messageId: 'sameConditionalBlock', - data: { - type: 'branch', - line: 2, + errors: [ + { + messageId: 'sameConditionalBlock', + data: { + type: 'branch', + line: 2, + }, + line: 4, }, - line: 4, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` if(a == 1) { doSomething(); } else if (a == 2) { @@ -216,32 +217,32 @@ describe('S1871', () => { } else if (a == 3) { doSomething(); }`, - errors: [ - { - messageId: 'sameConditionalBlock', - data: { - type: 'branch', - line: 2, - }, - line: 4, - }, - { - messageId: 'sameConditionalBlock', - data: { - type: 'branch', + errors: [ + { + messageId: 'sameConditionalBlock', + data: { + type: 'branch', + line: 2, + }, line: 4, }, - line: 6, - }, - ], - }, - ], - }); + { + messageId: 'sameConditionalBlock', + data: { + type: 'branch', + line: 4, + }, + line: 6, + }, + ], + }, + ], + }); - ruleTester.run('no-duplicated-branches switch', rule, { - valid: [ - { - code: ` + ruleTester.run('no-duplicated-branches switch', rule, { + valid: [ + { + code: ` function foo() { switch (a) { case 1: @@ -250,10 +251,10 @@ describe('S1871', () => { return first(); } }`, - }, - { - // small branches - code: ` + }, + { + // small branches + code: ` switch (a) { case 1: { // comment @@ -264,9 +265,9 @@ describe('S1871', () => { break; } }`, - }, - { - code: ` + }, + { + code: ` switch (a) { case 1: first(); @@ -276,9 +277,9 @@ describe('S1871', () => { second(); first(); }`, - }, - { - code: ` + }, + { + code: ` switch (a) { case 1: first(); @@ -287,11 +288,11 @@ describe('S1871', () => { case 2: third(); }`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` switch(a) { case 2: case 1: @@ -303,19 +304,19 @@ describe('S1871', () => { second(); break; }`, - errors: [ - { - messageId: 'sameConditionalBlock', - data: { - type: 'case', - line: '4', + errors: [ + { + messageId: 'sameConditionalBlock', + data: { + type: 'case', + line: '4', + }, + line: 8, }, - line: 8, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` switch (a) { case 1: first(); @@ -325,22 +326,22 @@ describe('S1871', () => { first(); second(); }`, - errors: [ - { - messageId: 'sameConditionalBlock', - data: { - type: 'case', - line: 3, + errors: [ + { + messageId: 'sameConditionalBlock', + data: { + type: 'case', + line: 3, + }, + line: 7, + endLine: 9, + column: 9, + endColumn: 20, }, - line: 7, - endLine: 9, - column: 9, - endColumn: 20, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` switch (a) { case 1: first(); @@ -351,32 +352,32 @@ describe('S1871', () => { second(); break; }`, - options: ['sonar-runtime'], - errors: [ - { - line: 7, - messageId: 'sonarRuntime', - data: { - type: 'case', - line: '3', - sonarRuntimeData: JSON.stringify({ - message: `This case's code block is the same as the block for the case on line 3.`, - secondaryLocations: [ - { - message: 'Original', - column: 8, - line: 3, - endColumn: 16, - endLine: 6, - }, - ], - }), + options: ['sonar-runtime'], + errors: [ + { + line: 7, + messageId: 'sonarRuntime', + data: { + type: 'case', + line: '3', + sonarRuntimeData: JSON.stringify({ + message: `This case's code block is the same as the block for the case on line 3.`, + secondaryLocations: [ + { + message: 'Original', + column: 8, + line: 3, + endColumn: 16, + endLine: 6, + }, + ], + }), + }, }, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` switch (a) { case 1: first(); @@ -391,19 +392,19 @@ describe('S1871', () => { first(); break; }`, - errors: [ - { - messageId: 'sameConditionalBlock', - line: 11, - data: { - type: 'case', - line: 3, + errors: [ + { + messageId: 'sameConditionalBlock', + line: 11, + data: { + type: 'case', + line: 3, + }, }, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` switch (a) { case 1: { first(); @@ -415,20 +416,20 @@ describe('S1871', () => { second(); } }`, - errors: [ - { - messageId: 'sameConditionalBlock', - line: 8, - data: { - type: 'case', - line: 3, + errors: [ + { + messageId: 'sameConditionalBlock', + line: 8, + data: { + type: 'case', + line: 3, + }, }, - }, - ], - }, - { - // check that for each branch we generate only one issue - code: ` + ], + }, + { + // check that for each branch we generate only one issue + code: ` switch (a) { case 1: first(); @@ -447,35 +448,35 @@ describe('S1871', () => { second(); break; }`, - errors: [ - { - messageId: 'sameConditionalBlock', - line: 7, - data: { - type: 'case', - line: 3, - }, - }, - { - messageId: 'sameConditionalBlock', - line: 11, - data: { - type: 'case', + errors: [ + { + messageId: 'sameConditionalBlock', line: 7, + data: { + type: 'case', + line: 3, + }, }, - }, - { - messageId: 'sameConditionalBlock', - line: 15, - data: { - type: 'case', + { + messageId: 'sameConditionalBlock', line: 11, + data: { + type: 'case', + line: 7, + }, + }, + { + messageId: 'sameConditionalBlock', + line: 15, + data: { + type: 'case', + line: 11, + }, }, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` switch(a) { case 1: doSomething(); @@ -484,19 +485,19 @@ describe('S1871', () => { doSomething(); break; }`, - errors: [ - { - messageId: 'sameConditionalBlock', - line: 6, - data: { - type: 'case', - line: 3, + errors: [ + { + messageId: 'sameConditionalBlock', + line: 6, + data: { + type: 'case', + line: 3, + }, }, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` switch(a) { case 0: foo(); @@ -512,17 +513,18 @@ describe('S1871', () => { second(); break; }`, - errors: [ - { - messageId: 'sameConditionalBlock', - line: 12, - data: { - type: 'case', - line: 8, + errors: [ + { + messageId: 'sameConditionalBlock', + line: 12, + data: { + type: 'case', + line: 8, + }, }, - }, - ], - }, - ], + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S1940/unit.test.ts b/packages/jsts/src/rules/S1940/unit.test.ts index 067d5b4ec6..025632cc9c 100644 --- a/packages/jsts/src/rules/S1940/unit.test.ts +++ b/packages/jsts/src/rules/S1940/unit.test.ts @@ -16,109 +16,111 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1940', () => { - const ruleTester = new RuleTester(); + it('S1940', () => { + const ruleTester = new RuleTester(); - ruleTester.run('no-inverted-boolean-check', rule, { - valid: [ - { - code: `if (!x) {}`, - }, - { - code: `if (x == 1) {}`, - }, - { - code: `if (!(x + 1)) {}`, - }, - { - code: `if (+(x == 1)) {}`, - }, - { - code: `!x ? 2 : 3`, - }, - ], - invalid: [ - // `==` => `!=` - { - code: `if (!(x == 1)) {}`, - errors: [ + ruleTester.run('no-inverted-boolean-check', rule, { + valid: [ + { + code: `if (!x) {}`, + }, + { + code: `if (x == 1) {}`, + }, + { + code: `if (!(x + 1)) {}`, + }, + { + code: `if (+(x == 1)) {}`, + }, + { + code: `!x ? 2 : 3`, + }, + ], + invalid: [ + // `==` => `!=` + { + code: `if (!(x == 1)) {}`, + errors: [ + { + ...error('!=', `if (x != 1) {}`), + line: 1, + endLine: 1, + column: 5, + endColumn: 14, + }, + ], + }, + // `!=` => `==` + { + code: `if (!(x != 1)) {}`, + errors: [error('==', `if (x == 1) {}`)], + }, + // `===` => `!==` + { + code: `if (!(x === 1)) {}`, + errors: [error('!==', `if (x !== 1) {}`)], + }, + // `!==` => `===` + { + code: `if (!(x !== 1)) {}`, + errors: [error('===', `if (x === 1) {}`)], + }, + // `>` => `<=` + { + code: `if (!(x > 1)) {}`, + errors: [error('<=', `if (x <= 1) {}`)], + }, + // `<` => `>=` + { + code: `if (!(x < 1)) {}`, + errors: [error('>=', `if (x >= 1) {}`)], + }, + // `>=` => `<` + { + code: `if (!(x >= 1)) {}`, + errors: [error('<', `if (x < 1) {}`)], + }, + // `<=` => `>` + { + code: `if (!(x <= 1)) {}`, + errors: [error('>', `if (x > 1) {}`)], + }, + // ternary operator + { + code: `!(x != 1) ? 1 : 2`, + errors: [error('==', `x == 1 ? 1 : 2`)], + }, + // not conditional + { + code: `foo(!(x === 1))`, + errors: [error('!==', `foo(x !== 1)`)], + }, + { + code: `let foo = !(x <= 4)`, + errors: [error('>', `let foo = x > 4`)], + }, + { + code: `let foo = !!(a < b)`, + errors: [error('>=', 'let foo = !(a >= b)')], + }, + ], + }); + + function error(invertedOperator: string, output: string) { + return { + messageId: 'useOppositeOperator', + data: { invertedOperator }, + suggestions: [ { - ...error('!=', `if (x != 1) {}`), - line: 1, - endLine: 1, - column: 5, - endColumn: 14, + messageId: 'suggestOperationInversion', + output, }, ], - }, - // `!=` => `==` - { - code: `if (!(x != 1)) {}`, - errors: [error('==', `if (x == 1) {}`)], - }, - // `===` => `!==` - { - code: `if (!(x === 1)) {}`, - errors: [error('!==', `if (x !== 1) {}`)], - }, - // `!==` => `===` - { - code: `if (!(x !== 1)) {}`, - errors: [error('===', `if (x === 1) {}`)], - }, - // `>` => `<=` - { - code: `if (!(x > 1)) {}`, - errors: [error('<=', `if (x <= 1) {}`)], - }, - // `<` => `>=` - { - code: `if (!(x < 1)) {}`, - errors: [error('>=', `if (x >= 1) {}`)], - }, - // `>=` => `<` - { - code: `if (!(x >= 1)) {}`, - errors: [error('<', `if (x < 1) {}`)], - }, - // `<=` => `>` - { - code: `if (!(x <= 1)) {}`, - errors: [error('>', `if (x > 1) {}`)], - }, - // ternary operator - { - code: `!(x != 1) ? 1 : 2`, - errors: [error('==', `x == 1 ? 1 : 2`)], - }, - // not conditional - { - code: `foo(!(x === 1))`, - errors: [error('!==', `foo(x !== 1)`)], - }, - { - code: `let foo = !(x <= 4)`, - errors: [error('>', `let foo = x > 4`)], - }, - { - code: `let foo = !!(a < b)`, - errors: [error('>=', 'let foo = !(a >= b)')], - }, - ], + }; + } }); - - function error(invertedOperator: string, output: string) { - return { - messageId: 'useOppositeOperator', - data: { invertedOperator }, - suggestions: [ - { - messageId: 'suggestOperationInversion', - output, - }, - ], - }; - } }); diff --git a/packages/jsts/src/rules/S1994/unit.test.ts b/packages/jsts/src/rules/S1994/unit.test.ts index bbd3a20097..3552d17f2c 100644 --- a/packages/jsts/src/rules/S1994/unit.test.ts +++ b/packages/jsts/src/rules/S1994/unit.test.ts @@ -16,15 +16,16 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S1994', () => { - const ruleTester = new RuleTester(); + it('S1994', () => { + const ruleTester = new RuleTester(); - ruleTester.run('Loop counter', rule, { - valid: [ - { - code: ` + ruleTester.run('Loop counter', rule, { + valid: [ + { + code: ` var i, j, k; for (i = 0; i < 3; i++) {} for (i = 0; i < 3; i+=1) {} @@ -44,25 +45,25 @@ describe('S1994', () => { for (i = 0; i < 3; ) {} for (i = 0; ; i++) {} `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` var i, j; for (i = 0; i < 3; j++) {} // Noncompliant`, - errors: [ - { - message: `This loop's stop condition tests "i" but the incrementer updates "j".`, - line: 3, - endLine: 3, - column: 7, - endColumn: 10, - }, - ], - }, - { - code: ` + errors: [ + { + message: `This loop's stop condition tests "i" but the incrementer updates "j".`, + line: 3, + endLine: 3, + column: 7, + endColumn: 10, + }, + ], + }, + { + code: ` var i, j, k; for (i = 0; i < 3; j+=1) {} for (i = 0; i < 3 && j < 4; k++) {} @@ -75,53 +76,54 @@ describe('S1994', () => { for (i = 0; i < 3; {y: x = 42 } = obj) {} for (i = 0; i < 3; { x = 42 } = obj) {} for (i = 0; i < 3; [x] = obj) {}`, - errors: [ - { - line: 3, - message: `This loop's stop condition tests "i" but the incrementer updates "j".`, - }, - { - line: 4, - message: `This loop's stop condition tests "i, j" but the incrementer updates "k".`, - }, - { - line: 5, - message: `This loop's stop condition tests "condition" but the incrementer updates "i".`, - }, - { - line: 6, - message: `This loop's stop condition tests "x" but the incrementer updates "z".`, - }, - { - line: 7, - message: `This loop's stop condition tests "this.i" but the incrementer updates "this.j".`, - }, - { - line: 8, - message: `This loop's stop condition tests "i" but the incrementer updates "j".`, - }, - { - line: 9, - message: `This loop's stop condition tests "i" but the incrementer updates "x".`, - }, - { - line: 10, - message: `This loop's stop condition tests "i" but the incrementer updates "x".`, - }, - { - line: 11, - message: `This loop's stop condition tests "i" but the incrementer updates "x".`, - }, - { - line: 12, - message: `This loop's stop condition tests "i" but the incrementer updates "x".`, - }, - { - line: 13, - message: `This loop's stop condition tests "i" but the incrementer updates "x".`, - }, - ], - }, - ], + errors: [ + { + line: 3, + message: `This loop's stop condition tests "i" but the incrementer updates "j".`, + }, + { + line: 4, + message: `This loop's stop condition tests "i, j" but the incrementer updates "k".`, + }, + { + line: 5, + message: `This loop's stop condition tests "condition" but the incrementer updates "i".`, + }, + { + line: 6, + message: `This loop's stop condition tests "x" but the incrementer updates "z".`, + }, + { + line: 7, + message: `This loop's stop condition tests "this.i" but the incrementer updates "this.j".`, + }, + { + line: 8, + message: `This loop's stop condition tests "i" but the incrementer updates "j".`, + }, + { + line: 9, + message: `This loop's stop condition tests "i" but the incrementer updates "x".`, + }, + { + line: 10, + message: `This loop's stop condition tests "i" but the incrementer updates "x".`, + }, + { + line: 11, + message: `This loop's stop condition tests "i" but the incrementer updates "x".`, + }, + { + line: 12, + message: `This loop's stop condition tests "i" but the incrementer updates "x".`, + }, + { + line: 13, + message: `This loop's stop condition tests "i" but the incrementer updates "x".`, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2004/unit.test.ts b/packages/jsts/src/rules/S2004/unit.test.ts index 2078eca04a..781c63b2cc 100644 --- a/packages/jsts/src/rules/S2004/unit.test.ts +++ b/packages/jsts/src/rules/S2004/unit.test.ts @@ -16,14 +16,15 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2004', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Functions should not be nested too deeply', rule, { - valid: [ - { - code: ` + it('S2004', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Functions should not be nested too deeply', rule, { + valid: [ + { + code: ` function f1() { function f2() { function f3() { @@ -31,11 +32,11 @@ describe('S2004', () => { } } }`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function f1() { function f2() { function f3() { @@ -43,9 +44,10 @@ describe('S2004', () => { } } }`, - options: [{ threshold: 2 }], - errors: 1, - }, - ], + options: [{ threshold: 2 }], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2068/unit.test.ts b/packages/jsts/src/rules/S2068/unit.test.ts index 154c9328da..0436ac8fc3 100644 --- a/packages/jsts/src/rules/S2068/unit.test.ts +++ b/packages/jsts/src/rules/S2068/unit.test.ts @@ -17,78 +17,80 @@ import { rule } from './index.js'; import { NoTypeCheckingRuleTester } from '../../../tests/tools/testers/rule-tester.js'; import path from 'path'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2068', () => { - const ruleTester = new NoTypeCheckingRuleTester(); + it('S2068', () => { + const ruleTester = new NoTypeCheckingRuleTester(); - const options = [{ passwordWords: ['password', 'pwd', 'passwd'] }]; + const options = [{ passwordWords: ['password', 'pwd', 'passwd'] }]; - ruleTester.run('Hard-coded passwords should be avoided', rule, { - valid: [ - { - code: `let password = ""`, - options, - }, - { - code: `let password = 'foo';`, - filename: path.join('some', 'L10n', 'path', 'file.js'), - options, - }, - ], - invalid: [ - { - code: `let password = "foo";`, - options, - errors: [ - { - message: 'Review this potentially hard-coded password.', - line: 1, - endLine: 1, - column: 16, - endColumn: 21, - }, - ], - }, - { - code: `let password = 'foo';`, - options, - errors: 1, - }, - { - code: ` + ruleTester.run('Hard-coded passwords should be avoided', rule, { + valid: [ + { + code: `let password = ""`, + options, + }, + { + code: `let password = 'foo';`, + filename: path.join('some', 'L10n', 'path', 'file.js'), + options, + }, + ], + invalid: [ + { + code: `let password = "foo";`, + options, + errors: [ + { + message: 'Review this potentially hard-coded password.', + line: 1, + endLine: 1, + column: 16, + endColumn: 21, + }, + ], + }, + { + code: `let password = 'foo';`, + options, + errors: 1, + }, + { + code: ` let my_pwd; my_pwd = "foo"; `, - options, - errors: 1, - }, - { - code: `let passwords = { user: "foo", passwd: "bar" };`, - options, - errors: 1, - }, - { - code: `let url = "https://example.com?password=hl2OAIXXZ60";`, - options, - errors: 1, - }, - { - code: `let secret = "foo"`, - options: [{ passwordWords: ['secret'] }], - errors: 1, - }, - { - code: `let url = "https://example.com?token=hl2OAIXXZ60";`, - options: [{ passwordWords: ['token'] }], - errors: 1, - }, - { - code: `let password = 'foo';`, - filename: path.join('some', 'random', 'path', 'file.js'), - options, - errors: 1, - }, - ], + options, + errors: 1, + }, + { + code: `let passwords = { user: "foo", passwd: "bar" };`, + options, + errors: 1, + }, + { + code: `let url = "https://example.com?password=hl2OAIXXZ60";`, + options, + errors: 1, + }, + { + code: `let secret = "foo"`, + options: [{ passwordWords: ['secret'] }], + errors: 1, + }, + { + code: `let url = "https://example.com?token=hl2OAIXXZ60";`, + options: [{ passwordWords: ['token'] }], + errors: 1, + }, + { + code: `let password = 'foo';`, + filename: path.join('some', 'random', 'path', 'file.js'), + options, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2077/unit.test.ts b/packages/jsts/src/rules/S2077/unit.test.ts index 69904c0cd7..374fd1a5a1 100644 --- a/packages/jsts/src/rules/S2077/unit.test.ts +++ b/packages/jsts/src/rules/S2077/unit.test.ts @@ -16,198 +16,200 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2077', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Formatting SQL queries is security-sensitive', rule, { - valid: [ - { - code: ` + it('S2077', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Formatting SQL queries is security-sensitive', rule, { + valid: [ + { + code: ` const mysql = require('mysql'); conn.query(sql, [userInput], (err, res) => {}); `, - }, - { - code: ` + }, + { + code: ` const mysql = require('mysql'); conn.query(sql, (err, res) => {}); `, - }, - { - code: ` + }, + { + code: ` const mysql = require('mysql'); conn.query(sql); `, - }, - { - code: ` + }, + { + code: ` const mysql = require('mysql'); conn.query(); `, - }, - { - code: ` + }, + { + code: ` const mysql = require('mysql'); conn.query("SELECT * FROM FOO"); `, - }, - { - code: ` + }, + { + code: ` const mysql = require('mysql'); conn.query("SELECT *" + " FROM FOO" + " WHERE BAR"); `, - }, - { - code: ` + }, + { + code: ` const mysql = require('mysql'); conn.query(foo("SELECT *" + userInput)); `, - }, - { - code: ` + }, + { + code: ` const mysql = require('mysql'); conn.query(\`SELECT * FROM FOO\`); `, - }, - { - code: ` + }, + { + code: ` const mysql = require('mysql'); sql = "select from " + userInput; conn.query(sql); `, - }, - { - code: ` + }, + { + code: ` const pg = require('pg'); conn.query(sql); `, - }, - { - code: ` + }, + { + code: ` const mysql2 = require('mysql2'); conn.query(sql); `, - }, - { - code: ` + }, + { + code: ` const sequelize = require('sequelize'); conn.query(sql); `, - }, - { - code: ` + }, + { + code: ` import { query } from 'myDB'; conn.query("select from " + userInput); `, - }, - { - // FN, userId is not escaped - code: ` + }, + { + // FN, userId is not escaped + code: ` const mysql = require('mysql'); conn.query("SELECT * FROM users WHERE id = ' + userId", [userInput], (err, res) => {}); `, - }, - { - code: ` + }, + { + code: ` require('mysql'); conn.query(x.foo());`, - }, - { - code: ` + }, + { + code: ` require('mysql'); conn.query(foo());`, - }, - { - code: ` + }, + { + code: ` require('mysql'); conn.query(concat());`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const mysql = require('mysql'); conn.query('SELECT * FROM users WHERE id = ' + userId, (err, res) => {});`, - errors: [ - { - message: 'Make sure that executing SQL queries is safe here.', - line: 3, - endLine: 3, - column: 7, - endColumn: 17, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Make sure that executing SQL queries is safe here.', + line: 3, + endLine: 3, + column: 7, + endColumn: 17, + }, + ], + }, + { + code: ` import { query } from 'pg'; conn.query('SELECT * FROM users WHERE id = ' + userId, (err, res => {})); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` import { query } from 'mysql2'; conn.query('SELECT * FROM users WHERE id = ' + userId, (err, res => {})); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` import { query } from 'sequelize'; conn.query('SELECT * FROM users WHERE id = ' + userId, (err, res => {})); `, - errors: 1, - }, - // FP, parameters are escaped - { - code: ` + errors: 1, + }, + // FP, parameters are escaped + { + code: ` const mysql = require('mysql'); conn.query('SELECT * FROM users WHERE id = ' + connection.escape(userId), (err, res => {})); `, - errors: 1, - }, + errors: 1, + }, - { - code: ` + { + code: ` require('mysql'); conn.query('a' + 'b' + x);`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` require('mysql'); conn.query('a' + x + 'b');`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` require('mysql'); conn.query(x + 'a' + 'b');`, - errors: 1, - }, + errors: 1, + }, - { - code: ` + { + code: ` require('mysql'); conn.query(\`a \${x} b\`);`, - errors: 1, - }, + errors: 1, + }, - { - code: ` + { + code: ` require('mysql'); conn.query(x.concat());`, - errors: 1, - }, + errors: 1, + }, - { - code: ` + { + code: ` require('mysql'); conn.query(x.replace());`, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2092/unit.test.ts b/packages/jsts/src/rules/S2092/unit.test.ts index dddaef0300..7846e0a97e 100644 --- a/packages/jsts/src/rules/S2092/unit.test.ts +++ b/packages/jsts/src/rules/S2092/unit.test.ts @@ -16,33 +16,34 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2092', () => { - const ruleTesterJs = new RuleTester(); - const ruleTesterTs = new RuleTester(); + it('S2092', () => { + const ruleTesterJs = new RuleTester(); + const ruleTesterTs = new RuleTester(); - const cookieSessionTestCases = { - valid: [ - { - code: ` + const cookieSessionTestCases = { + valid: [ + { + code: ` var cookieSession = require('cookie-session'); var session1 = cookieSession({ secret: "ddfdsfd", secure: true, }); `, - }, - { - code: ` + }, + { + code: ` var cookieSession = require('cookie-session'); var session1 = cookieSession({ secret: "ddfdsfd", }); // Compliant: by default secure is set to true on https connection `, - }, - { - code: ` + }, + { + code: ` var cookieSession = require('cookie-session'); var session1 = cookieSession("wrong argument"); var session1 = cookieSession(); @@ -55,31 +56,31 @@ describe('S2092', () => { secure: secureValue, }); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` var cookieSession = require('cookie-session'); var session1 = cookieSession({ secret: "ddfdsfd", secure: false, }); `, - errors: [ - { - message: - '{"message":"Make sure creating this cookie without the \\"secure\\" flag is safe.","secondaryLocations":[{"column":16,"line":5,"endColumn":21,"endLine":5}]}', - line: 3, - endLine: 3, - column: 22, - endColumn: 35, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: + '{"message":"Make sure creating this cookie without the \\"secure\\" flag is safe.","secondaryLocations":[{"column":16,"line":5,"endColumn":21,"endLine":5}]}', + line: 3, + endLine: 3, + column: 22, + endColumn: 35, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` var cookieSession = require('cookie-session'); const options = { secret: "ddfdsfd", @@ -87,20 +88,20 @@ describe('S2092', () => { }; var session1 = cookieSession(options); `, - errors: [ - { - message: - '{"message":"Make sure creating this cookie without the \\"secure\\" flag is safe.","secondaryLocations":[{"column":16,"line":5,"endColumn":21,"endLine":5},{"column":22,"line":3,"endColumn":7,"endLine":6}]}', - line: 7, - endLine: 7, - column: 22, - endColumn: 35, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: + '{"message":"Make sure creating this cookie without the \\"secure\\" flag is safe.","secondaryLocations":[{"column":16,"line":5,"endColumn":21,"endLine":5},{"column":22,"line":3,"endColumn":7,"endLine":6}]}', + line: 7, + endLine: 7, + column: 22, + endColumn: 35, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` var cookieSession = require('cookie-session'); const isSecure = false; const options = { @@ -109,25 +110,25 @@ describe('S2092', () => { }; var session1 = cookieSession(options); `, - errors: [ - { - message: - '{"message":"Make sure creating this cookie without the \\"secure\\" flag is safe.","secondaryLocations":[{"column":23,"line":3,"endColumn":28,"endLine":3},{"column":22,"line":4,"endColumn":7,"endLine":7}]}', - line: 8, - endLine: 8, - column: 22, - endColumn: 35, - }, - ], - options: ['sonar-runtime'], - }, - ], - }; + errors: [ + { + message: + '{"message":"Make sure creating this cookie without the \\"secure\\" flag is safe.","secondaryLocations":[{"column":23,"line":3,"endColumn":28,"endLine":3},{"column":22,"line":4,"endColumn":7,"endLine":7}]}', + line: 8, + endLine: 8, + column: 22, + endColumn: 35, + }, + ], + options: ['sonar-runtime'], + }, + ], + }; - const cookiesTestCases = { - valid: [ - { - code: ` + const cookiesTestCases = { + valid: [ + { + code: ` var Cookies = require('cookies'); var cookies = new Cookies(req, res, { @@ -138,9 +139,9 @@ describe('S2092', () => { }); // Compliant: by default secure is set to true on https connection cookies.set('LastVisit', new Date().toISOString(), { signed: true }); `, - }, - { - code: ` + }, + { + code: ` var Cookies = require('cookies') var cookies = new Cookies(req, res, { @@ -152,9 +153,9 @@ describe('S2092', () => { secure: true }); `, - }, - { - code: ` + }, + { + code: ` var Cookies = require('cookies') var cookies = new Cookies(req, res, { @@ -173,11 +174,11 @@ describe('S2092', () => { secure: secureValue }); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` var Cookies = require('cookies'); var cookies = new Cookies(req, res, { keys: keys }); cookies.set('LastVisit', new Date().toISOString(), { @@ -185,20 +186,20 @@ describe('S2092', () => { secure: false }); `, - errors: [ - { - message: - '{"message":"Make sure creating this cookie without the \\"secure\\" flag is safe.","secondaryLocations":[{"column":16,"line":6,"endColumn":21,"endLine":6}]}', - line: 4, - endLine: 4, - column: 7, - endColumn: 18, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: + '{"message":"Make sure creating this cookie without the \\"secure\\" flag is safe.","secondaryLocations":[{"column":16,"line":6,"endColumn":21,"endLine":6}]}', + line: 4, + endLine: 4, + column: 7, + endColumn: 18, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` var Cookies = require('cookies'); var cookies = new Cookies(req, res, { keys: keys }); var options = { @@ -207,20 +208,20 @@ describe('S2092', () => { }; cookies.set('LastVisit', new Date().toISOString(), options); `, - errors: [ - { - message: - '{"message":"Make sure creating this cookie without the \\"secure\\" flag is safe.","secondaryLocations":[{"column":16,"line":6,"endColumn":21,"endLine":6},{"column":20,"line":4,"endColumn":7,"endLine":7}]}', - line: 8, - endLine: 8, - column: 7, - endColumn: 18, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: + '{"message":"Make sure creating this cookie without the \\"secure\\" flag is safe.","secondaryLocations":[{"column":16,"line":6,"endColumn":21,"endLine":6},{"column":20,"line":4,"endColumn":7,"endLine":7}]}', + line: 8, + endLine: 8, + column: 7, + endColumn: 18, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` var Cookies = require('cookies'); var cookies = new Cookies(req, res, { keys: keys }); var secure = false; @@ -230,31 +231,31 @@ describe('S2092', () => { }; cookies.set('LastVisit', new Date().toISOString(), options); `, - errors: [ - { - message: - '{"message":"Make sure creating this cookie without the \\"secure\\" flag is safe.","secondaryLocations":[{"column":19,"line":4,"endColumn":24,"endLine":4},{"column":20,"line":5,"endColumn":7,"endLine":8}]}', - line: 9, - endLine: 9, - column: 7, - endColumn: 18, - }, - ], - options: ['sonar-runtime'], - }, - ], - }; + errors: [ + { + message: + '{"message":"Make sure creating this cookie without the \\"secure\\" flag is safe.","secondaryLocations":[{"column":19,"line":4,"endColumn":24,"endLine":4},{"column":20,"line":5,"endColumn":7,"endLine":8}]}', + line: 9, + endLine: 9, + column: 7, + endColumn: 18, + }, + ], + options: ['sonar-runtime'], + }, + ], + }; - const csurfTestCases = { - valid: [ - { - code: ` + const csurfTestCases = { + valid: [ + { + code: ` var csrf = require('csurf'); var csrfProtection = csrf({ cookie: { secure: true }}); `, - }, - { - code: ` + }, + { + code: ` var csrf = require('csurf'); var csrfProtection = csrf("unknown argument"); var csrfProtection = csrf({ cookie: "unknown"}); @@ -271,68 +272,68 @@ describe('S2092', () => { } var csrfProtection = csrf({ cookie: cookieValues}); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` var csrf = require('csurf'); var csrfProtection = csrf({ cookie: { secure: false }}); // Sensitive `, - errors: [ - { - message: - '{"message":"Make sure creating this cookie without the \\"secure\\" flag is safe.","secondaryLocations":[{"column":52,"line":3,"endColumn":57,"endLine":3}]}', - line: 3, - endLine: 3, - column: 28, - endColumn: 32, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: + '{"message":"Make sure creating this cookie without the \\"secure\\" flag is safe.","secondaryLocations":[{"column":52,"line":3,"endColumn":57,"endLine":3}]}', + line: 3, + endLine: 3, + column: 28, + endColumn: 32, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` var csrf = require('csurf'); var cookieObject = {cookie: {secure : false}}; var csrfProtection = csrf(cookieObject); // Sensitive `, - errors: [ - { - message: - '{"message":"Make sure creating this cookie without the \\"secure\\" flag is safe.","secondaryLocations":[{"column":44,"line":3,"endColumn":49,"endLine":3},{"column":25,"line":3,"endColumn":51,"endLine":3}]}', - line: 4, - endLine: 4, - column: 28, - endColumn: 32, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: + '{"message":"Make sure creating this cookie without the \\"secure\\" flag is safe.","secondaryLocations":[{"column":44,"line":3,"endColumn":49,"endLine":3},{"column":25,"line":3,"endColumn":51,"endLine":3}]}', + line: 4, + endLine: 4, + column: 28, + endColumn: 32, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` var csrf = require('csurf'); var csrfProtection = csrf({ cookie: true}); // Sensitive `, - errors: [ - { - message: - '{"message":"Make sure creating this cookie without the \\"secure\\" flag is safe.","secondaryLocations":[{"column":42,"line":3,"endColumn":46,"endLine":3}]}', - line: 3, - endLine: 3, - column: 28, - endColumn: 32, - }, - ], - options: ['sonar-runtime'], - }, - ], - }; + errors: [ + { + message: + '{"message":"Make sure creating this cookie without the \\"secure\\" flag is safe.","secondaryLocations":[{"column":42,"line":3,"endColumn":46,"endLine":3}]}', + line: 3, + endLine: 3, + column: 28, + endColumn: 32, + }, + ], + options: ['sonar-runtime'], + }, + ], + }; - const expressSessionTestCases = { - valid: [ - { - code: ` + const expressSessionTestCases = { + valid: [ + { + code: ` var express = require('express'); var session = require('express-session'); @@ -348,9 +349,9 @@ describe('S2092', () => { } })) // Compliant: by default secure is set to true on https `, - }, - { - code: ` + }, + { + code: ` var express = require('express'); var session = require('express-session'); @@ -367,9 +368,9 @@ describe('S2092', () => { } })); `, - }, - { - code: ` + }, + { + code: ` var express = require('express'); var session = require('express-session'); @@ -391,11 +392,11 @@ describe('S2092', () => { cookie: cookieValue })); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` var express = require('express'); var session = require('express-session'); @@ -412,52 +413,53 @@ describe('S2092', () => { } })); `, - errors: 1, - }, - ], - }; + errors: 1, + }, + ], + }; - ruleTesterJs.run( - '[JS express-session] Creating cookies without the "secure" flag is security-sensitive', - rule, - expressSessionTestCases, - ); - ruleTesterTs.run( - '[TS express-session] Creating cookies without the "secure" flag is security-sensitive', - rule, - expressSessionTestCases, - ); + ruleTesterJs.run( + '[JS express-session] Creating cookies without the "secure" flag is security-sensitive', + rule, + expressSessionTestCases, + ); + ruleTesterTs.run( + '[TS express-session] Creating cookies without the "secure" flag is security-sensitive', + rule, + expressSessionTestCases, + ); - ruleTesterJs.run( - '[JS cookie-session] Creating cookies without the "secure" flag is security-sensitive', - rule, - cookieSessionTestCases, - ); - ruleTesterTs.run( - '[TS cookie-session] Creating cookies without the "secure" flag is security-sensitive', - rule, - cookieSessionTestCases, - ); + ruleTesterJs.run( + '[JS cookie-session] Creating cookies without the "secure" flag is security-sensitive', + rule, + cookieSessionTestCases, + ); + ruleTesterTs.run( + '[TS cookie-session] Creating cookies without the "secure" flag is security-sensitive', + rule, + cookieSessionTestCases, + ); - ruleTesterJs.run( - '[JS cookies] Creating cookies without the "secure" flag is security-sensitive', - rule, - cookiesTestCases, - ); - ruleTesterTs.run( - '[TS cookies] Creating cookies without the "secure" flag is security-sensitive', - rule, - cookiesTestCases, - ); + ruleTesterJs.run( + '[JS cookies] Creating cookies without the "secure" flag is security-sensitive', + rule, + cookiesTestCases, + ); + ruleTesterTs.run( + '[TS cookies] Creating cookies without the "secure" flag is security-sensitive', + rule, + cookiesTestCases, + ); - ruleTesterJs.run( - '[JS csurf] Creating cookies without the "secure" flag is security-sensitive', - rule, - csurfTestCases, - ); - ruleTesterTs.run( - '[TS csurf] Creating cookies without the "secure" flag is security-sensitive', - rule, - csurfTestCases, - ); + ruleTesterJs.run( + '[JS csurf] Creating cookies without the "secure" flag is security-sensitive', + rule, + csurfTestCases, + ); + ruleTesterTs.run( + '[TS csurf] Creating cookies without the "secure" flag is security-sensitive', + rule, + csurfTestCases, + ); + }); }); diff --git a/packages/jsts/src/rules/S2123/unit.test.ts b/packages/jsts/src/rules/S2123/unit.test.ts index d367c76e55..42530ce41c 100644 --- a/packages/jsts/src/rules/S2123/unit.test.ts +++ b/packages/jsts/src/rules/S2123/unit.test.ts @@ -16,72 +16,74 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2123', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Values should not be uselessly incremented', rule, { - valid: [ - { - code: `i = j++;`, - }, - { - code: `i = ++i;`, - }, - { - code: `i++;`, - }, - { - code: `function f1() { + it('S2123', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Values should not be uselessly incremented', rule, { + valid: [ + { + code: `i = j++;`, + }, + { + code: `i = ++i;`, + }, + { + code: `i++;`, + }, + { + code: `function f1() { let i = 1; i++; }`, - }, - { - code: `let outside = 1; + }, + { + code: `let outside = 1; function f1() { return outside++; }`, - }, - { - code: `function f1() { + }, + { + code: `function f1() { let i = 1; return ++i; }`, - }, - ], - invalid: [ - { - code: `i = i++;`, - errors: [ - { - message: 'Remove this increment or correct the code not to waste it.', - line: 1, - endLine: 1, - column: 5, - endColumn: 8, - }, - ], - }, - { - code: `i = i--; `, - errors: [ - { - message: 'Remove this decrement or correct the code not to waste it.', - }, - ], - }, - { - code: `function f1() { + }, + ], + invalid: [ + { + code: `i = i++;`, + errors: [ + { + message: 'Remove this increment or correct the code not to waste it.', + line: 1, + endLine: 1, + column: 5, + endColumn: 8, + }, + ], + }, + { + code: `i = i--; `, + errors: [ + { + message: 'Remove this decrement or correct the code not to waste it.', + }, + ], + }, + { + code: `function f1() { let i = 1; return i++; }`, - errors: [ - { - message: 'Remove this increment or correct the code not to waste it.', - }, - ], - }, - ], + errors: [ + { + message: 'Remove this increment or correct the code not to waste it.', + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2137/unit.test.ts b/packages/jsts/src/rules/S2137/unit.test.ts index b1c9df514a..09a478409b 100644 --- a/packages/jsts/src/rules/S2137/unit.test.ts +++ b/packages/jsts/src/rules/S2137/unit.test.ts @@ -16,29 +16,30 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTester = new RuleTester(); describe('S2137', () => { - ruleTester.run('Special identifiers should not be bound or assigned', rule, { - valid: [ - { - code: `eval("");`, - }, - { - code: `function foo(a){ + it('S2137', () => { + ruleTester.run('Special identifiers should not be bound or assigned', rule, { + valid: [ + { + code: `eval("");`, + }, + { + code: `function foo(a){ arguments[0] = a; a = arguments; }`, - }, - { - code: `var fun = function(){fun(arguments);} + }, + { + code: `var fun = function(){fun(arguments);} var f = new Function("arguments", "return 17;"); var obj = { set p(arg) { } };`, - }, - { - code: `function fun() { + }, + { + code: `function fun() { var a = arguments.length == 0; // OK var b = arguments.length === 0; // OK } @@ -49,103 +50,103 @@ describe('S2137', () => { function fun(yield) { // OK } `, - }, - { - code: ` + }, + { + code: ` (function( global, undefined ) { })(this); `, - }, - { code: 'var hasOwnProperty = Object.prototype.hasOwnProperty' }, - { code: 'const toString = Object.prototype.hasOwnProperty' }, - { code: 'function escape(html, encode) { return html; }' }, - { code: 'function unescape(html) { return html; }' }, - { code: 'const toString = {}.toString()' }, - { - code: `// @flow + }, + { code: 'var hasOwnProperty = Object.prototype.hasOwnProperty' }, + { code: 'const toString = Object.prototype.hasOwnProperty' }, + { code: 'function escape(html, encode) { return html; }' }, + { code: 'function unescape(html) { return html; }' }, + { code: 'const toString = {}.toString()' }, + { + code: `// @flow function f(argWithFunctionType: (user) => void) {} `, - }, - ], - invalid: [ - { - code: `eval = 42; + }, + ], + invalid: [ + { + code: `eval = 42; function fun(){arguments++}`, - errors: [ - { - message: `Remove the modification of "eval".`, - line: 1, - endLine: 1, - column: 1, - endColumn: 5, - }, - { - message: `Remove the modification of "arguments".`, - line: 2, - endLine: 2, - column: 29, - endColumn: 38, - }, - ], - }, - { - code: `function x(eval) { } + errors: [ + { + message: `Remove the modification of "eval".`, + line: 1, + endLine: 1, + column: 1, + endColumn: 5, + }, + { + message: `Remove the modification of "arguments".`, + line: 2, + endLine: 2, + column: 29, + endColumn: 38, + }, + ], + }, + { + code: `function x(eval) { } var obj = { set p(arguments) { } }; `, - errors: [ - { - message: `Do not use "eval" to declare a parameter - use another name.`, - }, - { - message: `Do not use "arguments" to declare a parameter - use another name.`, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Do not use "eval" to declare a parameter - use another name.`, + }, + { + message: `Do not use "arguments" to declare a parameter - use another name.`, + }, + ], + }, + { + code: ` let eval; function fun(){var arguments;}`, - errors: [ - { - message: `Do not use "eval" to declare a variable - use another name.`, - }, - { - message: `Do not use "arguments" to declare a variable - use another name.`, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Do not use "eval" to declare a variable - use another name.`, + }, + { + message: `Do not use "arguments" to declare a variable - use another name.`, + }, + ], + }, + { + code: ` var y = function eval() { }; function arguments() { }`, - errors: [ - { - message: `Do not use "eval" to declare a function - use another name.`, - }, - { - message: `Do not use "arguments" to declare a function - use another name.`, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Do not use "eval" to declare a function - use another name.`, + }, + { + message: `Do not use "arguments" to declare a function - use another name.`, + }, + ], + }, + { + code: ` NaN = 42; Infinity = 42; undefined = 42; `, - errors: [ - { - message: `Remove the modification of "NaN".`, - }, - { - message: `Remove the modification of "Infinity".`, - }, - { - message: `Remove the modification of "undefined".`, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Remove the modification of "NaN".`, + }, + { + message: `Remove the modification of "Infinity".`, + }, + { + message: `Remove the modification of "undefined".`, + }, + ], + }, + { + code: ` function fun() { var c = (arguments = 0) == 0; } @@ -156,10 +157,10 @@ describe('S2137', () => { var f = function(eval) {} const arguments = eval; var arrowFunction = (arguments) => {}`, - errors: 8, - }, - { - code: ` + errors: 8, + }, + { + code: ` /** * Destructuring patern in declaration */ @@ -177,74 +178,75 @@ describe('S2137', () => { let arguments = eval; } `, - errors: 4, - }, - { - code: ` + errors: 4, + }, + { + code: ` function fun (eval = 1) { } function foo([arguments, eval]) { } `, - errors: 3, - }, - { - code: ` + errors: 3, + }, + { + code: ` function foo() { var NaN; } function foo() { var Infinity; } function foo() { var undefined; } function foo(undefined) { var x = undefined; }`, - errors: 2, - }, - { - code: ` + errors: 2, + }, + { + code: ` function foo() { var NaN; } function foo() { var Infinity; } function foo() { var undefined = 42; } function foo(undefined = 42) { var x = undefined; }`, - errors: 4, - }, - { - code: ` + errors: 4, + }, + { + code: ` const {obj, ...eval} = foo(); `, - errors: 1, - }, - { - code: "String = 'hello world';", - errors: 1, - }, - { - code: 'String++;', - errors: 1, - }, - { - code: '({Object = 0, String = 0} = {});', - errors: 2, - }, - { - code: 'Array = 1;', - errors: 1, - }, - { - code: 'Number = 1;', - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: "String = 'hello world';", + errors: 1, + }, + { + code: 'String++;', + errors: 1, + }, + { + code: '({Object = 0, String = 0} = {});', + errors: 2, + }, + { + code: 'Array = 1;', + errors: 1, + }, + { + code: 'Number = 1;', + errors: 1, + }, + { + code: ` (function( global, undefined = 42) { })(this); `, - errors: [ - { - message: `Do not use "undefined" to declare a parameter - use another name.`, - line: 2, - endLine: 2, - column: 28, - endColumn: 37, - }, - ], - }, - ], + errors: [ + { + message: `Do not use "undefined" to declare a parameter - use another name.`, + line: 2, + endLine: 2, + column: 28, + endColumn: 37, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2138/unit.test.ts b/packages/jsts/src/rules/S2138/unit.test.ts index 6951d66007..d8414fcb1a 100644 --- a/packages/jsts/src/rules/S2138/unit.test.ts +++ b/packages/jsts/src/rules/S2138/unit.test.ts @@ -16,7 +16,7 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const tests = { valid: [ @@ -62,6 +62,8 @@ const ruleTesterJs = new RuleTester(); const ruleTesterTs = new RuleTester(); describe('S2138', () => { - ruleTesterJs.run('"undefined" should not be assigned [js]', rule, tests); - ruleTesterTs.run('"undefined" should not be assigned [ts]', rule, tests); + it('S2138', () => { + ruleTesterJs.run('"undefined" should not be assigned [js]', rule, tests); + ruleTesterTs.run('"undefined" should not be assigned [ts]', rule, tests); + }); }); diff --git a/packages/jsts/src/rules/S2187/unit.test.ts b/packages/jsts/src/rules/S2187/unit.test.ts index 2439c47b0d..d5716240c3 100644 --- a/packages/jsts/src/rules/S2187/unit.test.ts +++ b/packages/jsts/src/rules/S2187/unit.test.ts @@ -16,79 +16,81 @@ */ import { DefaultParserRuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2187', () => { - const ruleTester = new DefaultParserRuleTester(); - ruleTester.run('Test files should contain at least one test case', rule, { - valid: [ - { - code: `/* empty main file */`, - filename: 'foo.js', - }, - { - code: ` + it('S2187', () => { + const ruleTester = new DefaultParserRuleTester(); + ruleTester.run('Test files should contain at least one test case', rule, { + valid: [ + { + code: `/* empty main file */`, + filename: 'foo.js', + }, + { + code: ` /* a test file using 'it' */ it('1 + 2 should give 3', () => { expect(1 + 2).toBe(3) });`, - filename: 'foo.test.js', - }, - { - code: ` + filename: 'foo.test.js', + }, + { + code: ` /* a test file using 'it.only' */ it.only('1 + 2 should give 3', () => { expect(1 + 2).toBe(3) });`, - filename: 'foo.test.js', - }, - { - code: ` + filename: 'foo.test.js', + }, + { + code: ` /* a test file using 'test' */ test('1 + 2 should give 3', () => { expect(1 + 2).toBe(3) });`, - filename: 'foo.test.js', - }, - { - code: ` + filename: 'foo.test.js', + }, + { + code: ` /* a test file using 'test.only' */ test.only('1 + 2 should give 3', () => { expect(1 + 2).toBe(3) });`, - filename: 'foo.test.js', - }, - { - code: ` + filename: 'foo.test.js', + }, + { + code: ` /* a spec file using 'it' */ it('1 + 2 should give 3', () => { expect(1 + 2).toBe(3) });`, - filename: 'foo.spec.js', - }, - ], - invalid: [ - { - code: `/* empty test file */`, - filename: 'foo.test.js', - errors: [ - { - message: 'Add some tests to this file or delete it.', - line: 0, - column: 1, - }, - ], - }, - { - code: `/* empty spec file */`, - filename: 'foo.spec.js', - errors: 1, - }, - { - code: `it['coverage']();`, - filename: 'foo.spec.js', - errors: 1, - }, - ], + filename: 'foo.spec.js', + }, + ], + invalid: [ + { + code: `/* empty test file */`, + filename: 'foo.test.js', + errors: [ + { + message: 'Add some tests to this file or delete it.', + line: 0, + column: 1, + }, + ], + }, + { + code: `/* empty spec file */`, + filename: 'foo.spec.js', + errors: 1, + }, + { + code: `it['coverage']();`, + filename: 'foo.spec.js', + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2189/unit.test.ts b/packages/jsts/src/rules/S2189/unit.test.ts index 425b3fe665..052d9018f8 100644 --- a/packages/jsts/src/rules/S2189/unit.test.ts +++ b/packages/jsts/src/rules/S2189/unit.test.ts @@ -16,22 +16,23 @@ */ import { DefaultParserRuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2189', () => { - const ruleTester = new DefaultParserRuleTester(); + it('S2189', () => { + const ruleTester = new DefaultParserRuleTester(); - ruleTester.run('Loops should not be infinite', rule, { - valid: [ - { - code: ` + ruleTester.run('Loops should not be infinite', rule, { + valid: [ + { + code: ` for (var i=0;i<5;i++) { console.log("hello"); } `, - }, - { - code: ` + }, + { + code: ` var j = 0; while (true) { // reachable end condition added j++; @@ -40,9 +41,9 @@ describe('S2189', () => { } } `, - }, - { - code: ` + }, + { + code: ` function * generator() { while(true) { // OK (yield in the loop) foo(); @@ -50,9 +51,9 @@ describe('S2189', () => { } } `, - }, - { - code: ` + }, + { + code: ` function someFunction() { while(true) { // OK (return in the loop) foo(); @@ -60,9 +61,9 @@ describe('S2189', () => { } } `, - }, - { - code: ` + }, + { + code: ` const sleep = time => { let count = 0; const waitTill = new Date(new Date().getTime() + time); @@ -71,9 +72,9 @@ describe('S2189', () => { } }; `, - }, - { - code: ` + }, + { + code: ` function do_while() { var trueValue = true; @@ -83,9 +84,9 @@ describe('S2189', () => { } while (trueValue); } `, - }, - { - code: ` + }, + { + code: ` function always_true() { var trueValue = true; @@ -95,9 +96,9 @@ describe('S2189', () => { } } `, - }, - { - code: ` + }, + { + code: ` function throws_interrupts_loop() { for(;;) { // OK throw "We are leaving!"; @@ -110,16 +111,16 @@ describe('S2189', () => { } } `, - }, - { - code: ` + }, + { + code: ` while (until === undefined) { until = getUntil(); } `, - }, - { - code: ` + }, + { + code: ` outer: while (true) { while (true) { @@ -128,9 +129,9 @@ describe('S2189', () => { } } `, - }, - { - code: ` + }, + { + code: ` while (true) { // FN inner: while (true) { @@ -139,98 +140,98 @@ describe('S2189', () => { } } `, - }, - { - code: ` + }, + { + code: ` let xs = [1, 2, 3]; while (xs) { doSomething(xs.pop()); }`, - }, - { - code: ` + }, + { + code: ` let xs = [1, 2, 3]; while (xs) { doSomething(xs); }`, - }, - { - code: ` + }, + { + code: ` var parent = $container.find('.list')[0]; while (parent && parent.firstChild) { parent.removeChild(parent.firstChild); }`, - }, - { - code: ` + }, + { + code: ` let coverage = [1, 2, 3]; while (coverage) { coverage.length; doSomething(coverage); }`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` var k = 0; var b = true; while (b) { // Noncompliant; b never written to in loop k++; } `, - errors: [ - { - line: 4, - endLine: 4, - column: 14, - endColumn: 15, - message: "'b' is not modified in this loop.", - }, - ], - }, - { - code: ` + errors: [ + { + line: 4, + endLine: 4, + column: 14, + endColumn: 15, + message: "'b' is not modified in this loop.", + }, + ], + }, + { + code: ` while (true) { console.log("hello"); } `, - errors: [ - { - line: 2, - endLine: 2, - column: 7, - endColumn: 12, - message: "Correct this loop's end condition to not be invariant.", - }, - ], - }, - { - code: ` + errors: [ + { + line: 2, + endLine: 2, + column: 7, + endColumn: 12, + message: "Correct this loop's end condition to not be invariant.", + }, + ], + }, + { + code: ` for (;;) { console.log("hello"); } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` for (var str = '';str >= '0' && '9' >= str;) { console.log("hello"); } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` for (;true;) { console.log("hello"); } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` while (true) { // Noncompliant while (true) { if (cond) { @@ -239,34 +240,35 @@ describe('S2189', () => { } } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` do { console.log("hello"); } while (true); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` while (true) { function doSomething() { return "hello"; } } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` while (true) { var a = function () {return 0;}; } `, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2201/unit.test.ts b/packages/jsts/src/rules/S2201/unit.test.ts index 1fbe09966e..06dc56ade1 100644 --- a/packages/jsts/src/rules/S2201/unit.test.ts +++ b/packages/jsts/src/rules/S2201/unit.test.ts @@ -16,15 +16,19 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2201', () => { - const ruleTester = new RuleTester(); + it('S2201', () => { + const ruleTester = new RuleTester(); - ruleTester.run('Return values from functions without side effects should not be ignored', rule, { - valid: [ + ruleTester.run( + 'Return values from functions without side effects should not be ignored', + rule, { - code: ` + valid: [ + { + code: ` function returnIsNotIgnored() { var x = "abc".concat("bcd"); @@ -32,9 +36,9 @@ describe('S2201', () => { return true; } }`, - }, - { - code: ` + }, + { + code: ` function noSupportForUserTypes() { class A { methodWithoutSideEffect() { @@ -44,22 +48,22 @@ describe('S2201', () => { (new A()).methodWithoutSideEffect(); // OK }`, - }, - { - code: ` + }, + { + code: ` function unknownType(x: any) { x.foo(); }`, - }, - { - code: ` + }, + { + code: ` function computedPropertyOnDestructuring(source: any, property: string) { // OK, used as computed property name const { [property]: _, ...rest } = source; return rest; }`, - }, - { - code: ` + }, + { + code: ` // "some" and "every" are sometimes used to provide early termination for loops // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach [1, 2, 3].some(function(el) { @@ -70,56 +74,56 @@ describe('S2201', () => { return ! el !== 2; }); `, - }, - { - code: ` + }, + { + code: ` function methodsOnString() { // "replace" with callback is OK "abc".replace(/ab/, () => ""); "abc".replace(/ab/, function() {return ""}); }`, - }, - { - code: ` + }, + { + code: ` function myCallBack() {} function methodsOnString() { // "replace" with callback is OK "abc".replace(/ab/, myCallBack); }`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function methodsOnMath() { let x = -42; Math.abs(x); }`, - errors: [ - { - messageId: `returnValueMustBeUsed`, - data: { methodName: 'abs' }, - line: 4, - endLine: 4, - column: 9, - endColumn: 20, + errors: [ + { + messageId: `returnValueMustBeUsed`, + data: { methodName: 'abs' }, + line: 4, + endLine: 4, + column: 9, + endColumn: 20, + }, + ], }, - ], - }, - { - code: ` + { + code: ` function mapOnArray() { let arr = [1, 2, 3]; arr.map(function(x){ }); }`, - errors: [ - { - messageId: `useForEach`, + errors: [ + { + messageId: `useForEach`, + }, + ], }, - ], - }, - { - code: ` + { + code: ` function methodsOnArray(arr1: any[]) { let arr = [1, 2, 3]; @@ -127,27 +131,27 @@ describe('S2201', () => { arr1.join(","); }`, - errors: [ - { - messageId: 'returnValueMustBeUsed', - data: { methodName: 'slice' }, - line: 5, - column: 9, - endLine: 5, - endColumn: 24, + errors: [ + { + messageId: 'returnValueMustBeUsed', + data: { methodName: 'slice' }, + line: 5, + column: 9, + endLine: 5, + endColumn: 24, + }, + { + messageId: 'returnValueMustBeUsed', + data: { methodName: 'join' }, + line: 7, + column: 9, + endLine: 7, + endColumn: 23, + }, + ], }, { - messageId: 'returnValueMustBeUsed', - data: { methodName: 'join' }, - line: 7, - column: 9, - endLine: 7, - endColumn: 23, - }, - ], - }, - { - code: ` + code: ` function methodsOnString() { let x = "abc"; x.concat("abc"); @@ -155,75 +159,77 @@ describe('S2201', () => { "abc".concat("bcd").charCodeAt(2); "abc".replace(/ab/, "d"); }`, - errors: [ - { - messageId: 'returnValueMustBeUsed', - data: { methodName: 'concat' }, - line: 4, - column: 9, - endLine: 4, - endColumn: 24, - }, - { - messageId: 'returnValueMustBeUsed', - data: { methodName: 'concat' }, - line: 5, - column: 9, - endLine: 5, - endColumn: 28, - }, - { - messageId: 'returnValueMustBeUsed', - data: { methodName: 'charCodeAt' }, - line: 6, - column: 9, - endLine: 6, - endColumn: 42, + errors: [ + { + messageId: 'returnValueMustBeUsed', + data: { methodName: 'concat' }, + line: 4, + column: 9, + endLine: 4, + endColumn: 24, + }, + { + messageId: 'returnValueMustBeUsed', + data: { methodName: 'concat' }, + line: 5, + column: 9, + endLine: 5, + endColumn: 28, + }, + { + messageId: 'returnValueMustBeUsed', + data: { methodName: 'charCodeAt' }, + line: 6, + column: 9, + endLine: 6, + endColumn: 42, + }, + { + messageId: 'returnValueMustBeUsed', + data: { methodName: 'replace' }, + line: 7, + column: 9, + endLine: 7, + endColumn: 33, + }, + ], }, { - messageId: 'returnValueMustBeUsed', - data: { methodName: 'replace' }, - line: 7, - column: 9, - endLine: 7, - endColumn: 33, - }, - ], - }, - { - code: ` + code: ` function methodsOnNumbers() { var num = 43 * 53; num.toExponential(); }`, - errors: [ - { - messageId: 'returnValueMustBeUsed', - data: { methodName: 'toExponential' }, - line: 4, - column: 9, - endLine: 4, - endColumn: 28, + errors: [ + { + messageId: 'returnValueMustBeUsed', + data: { methodName: 'toExponential' }, + line: 4, + column: 9, + endLine: 4, + endColumn: 28, + }, + ], }, - ], - }, - { - code: ` + { + code: ` function methodsOnRegexp() { var regexp = /abc/; regexp.test("my string"); }`, - errors: [ - { - messageId: 'returnValueMustBeUsed', - data: { methodName: 'test' }, - line: 4, - column: 9, - endLine: 4, - endColumn: 33, + errors: [ + { + messageId: 'returnValueMustBeUsed', + data: { methodName: 'test' }, + line: 4, + column: 9, + endLine: 4, + endColumn: 33, + }, + ], }, ], }, - ], + ); }); }); diff --git a/packages/jsts/src/rules/S2208/unit.test.ts b/packages/jsts/src/rules/S2208/unit.test.ts index 22346e5909..56ba37c0e6 100644 --- a/packages/jsts/src/rules/S2208/unit.test.ts +++ b/packages/jsts/src/rules/S2208/unit.test.ts @@ -16,59 +16,61 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTesterJS = new RuleTester(); describe('S2208', () => { - ruleTesterJS.run('Wildcard imports should not be used', rule, { - valid: [ - { - code: ` + it('S2208', () => { + ruleTesterJS.run('Wildcard imports should not be used', rule, { + valid: [ + { + code: ` import a from 'aa'; // ImportDefaultSpecifier import { b } from 'bb'; // ImportSpecifier import { c, d } from 'cd'; // ImportSpecifier import { e as f } from 'e'; // ImportSpecifier`, - }, - { - code: `export { m } from "module-name";`, - }, - ], - invalid: [ - { - code: ` + }, + { + code: `export { m } from "module-name";`, + }, + ], + invalid: [ + { + code: ` import * as name1 from "module-name"; import defaultMember, * as name2 from "module-name"; `, - errors: [ - { - message: `Explicitly import the specific member needed.`, - line: 2, - endLine: 2, - column: 14, - endColumn: 24, - }, - { - message: `Explicitly import the specific member needed.`, - line: 3, - endLine: 3, - column: 29, - endColumn: 39, - }, - ], - }, - { - code: `export * from "module-name";`, - errors: [ - { - message: `Explicitly export the specific member needed.`, - line: 1, - endLine: 1, - column: 1, - endColumn: 29, - }, - ], - }, - ], + errors: [ + { + message: `Explicitly import the specific member needed.`, + line: 2, + endLine: 2, + column: 14, + endColumn: 24, + }, + { + message: `Explicitly import the specific member needed.`, + line: 3, + endLine: 3, + column: 29, + endColumn: 39, + }, + ], + }, + { + code: `export * from "module-name";`, + errors: [ + { + message: `Explicitly export the specific member needed.`, + line: 1, + endLine: 1, + column: 1, + endColumn: 29, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2234/unit.test.ts b/packages/jsts/src/rules/S2234/unit.test.ts index 20813f174d..b93ae2b4fe 100644 --- a/packages/jsts/src/rules/S2234/unit.test.ts +++ b/packages/jsts/src/rules/S2234/unit.test.ts @@ -16,14 +16,15 @@ */ import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2234', () => { - const eslintRuleTester = new DefaultParserRuleTester({ sourceType: 'script' }); - eslintRuleTester.run('Parameters should be passed in the correct order', rule, { - valid: [ - { - code: ` + it('S2234', () => { + const eslintRuleTester = new DefaultParserRuleTester({ sourceType: 'script' }); + eslintRuleTester.run('Parameters should be passed in the correct order', rule, { + valid: [ + { + code: ` function f1(p1, p2, p3) {} function f2(p1, p2, p3) {} function f2() {} @@ -48,9 +49,9 @@ describe('S2234', () => { withInitializer(p1, p2); arrayBindingPattern(p2, p1); }`, - }, - { - code: ` + }, + { + code: ` function f(p1, p2) {} if (p1 < p2) { f(p2, p1); @@ -62,53 +63,53 @@ describe('S2234', () => { f(p2, p1); } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function f1(p1, p2, p3) {} f1(p2, p1, p3);`, - errors: [ - { - message: `{"message":"Arguments 'p2' and 'p1' have the same names but not the same order as the function parameters.","secondaryLocations":[{"message":"Formal parameters","column":20,"line":2,"endColumn":30,"endLine":2}]}`, - line: 3, - endLine: 3, - column: 12, - endColumn: 22, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: `{"message":"Arguments 'p2' and 'p1' have the same names but not the same order as the function parameters.","secondaryLocations":[{"message":"Formal parameters","column":20,"line":2,"endColumn":30,"endLine":2}]}`, + line: 3, + endLine: 3, + column: 12, + endColumn: 22, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` (function(p1, p2) {})(p2, p1);`, - errors: [ - { - message: `{"message":"Arguments 'p2' and 'p1' have the same names but not the same order as the function parameters.","secondaryLocations":[{"message":"Formal parameters","column":18,"line":2,"endColumn":24,"endLine":2}]}`, - line: 2, - endLine: 2, - column: 31, - endColumn: 37, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: `{"message":"Arguments 'p2' and 'p1' have the same names but not the same order as the function parameters.","secondaryLocations":[{"message":"Formal parameters","column":18,"line":2,"endColumn":24,"endLine":2}]}`, + line: 2, + endLine: 2, + column: 31, + endColumn: 37, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` function withInitializer(p1="", p2="") {} withInitializer(p2, p1);`, - errors: [ - { - message: `{"message":"Arguments 'p2' and 'p1' have the same names but not the same order as the function parameters.","secondaryLocations":[{"message":"Formal parameters","column":33,"line":2,"endColumn":45,"endLine":2}]}`, - line: 3, - endLine: 3, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: `{"message":"Arguments 'p2' and 'p1' have the same names but not the same order as the function parameters.","secondaryLocations":[{"message":"Formal parameters","column":33,"line":2,"endColumn":45,"endLine":2}]}`, + line: 3, + endLine: 3, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` function f(p1, p2) {} if (p1 = p2) { f(p2, p1); @@ -126,16 +127,16 @@ describe('S2234', () => { f(p2, p1); } `, - errors: 5, - }, - ], - }); + errors: 5, + }, + ], + }); - const typeScriptRuleTester = new RuleTester(); - typeScriptRuleTester.run('Parameters should be passed in the correct order', rule, { - valid: [ - { - code: ` + const typeScriptRuleTester = new RuleTester(); + typeScriptRuleTester.run('Parameters should be passed in the correct order', rule, { + valid: [ + { + code: ` const a = 1, b = 2, c = 3, d = 4, x = "", y = 5; export function sameType(a: number, b: number, c = 3) {} @@ -181,28 +182,28 @@ describe('S2234', () => { new A().sameType(42, a, c); new A().sameType(a, d, b); new A().differentTypes(y, x);`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function differentTypes(x: string, y: number, z = 42) {} function nokForSameType(z: number, y: number) { differentTypes("hello", z, y); // Noncompliant }`, - errors: [ - { - message: `{"message":"Arguments 'z' and 'y' have the same names but not the same order as the function parameters.","secondaryLocations":[{"message":"Formal parameters","column":32,"line":2,"endColumn":60,"endLine":2}]}`, - line: 4, - endLine: 4, - column: 26, - endColumn: 39, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: `{"message":"Arguments 'z' and 'y' have the same names but not the same order as the function parameters.","secondaryLocations":[{"message":"Formal parameters","column":32,"line":2,"endColumn":60,"endLine":2}]}`, + line: 4, + endLine: 4, + column: 26, + endColumn: 39, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` interface A { prop1: number } @@ -210,22 +211,22 @@ describe('S2234', () => { ((a1: A, a2: A) => {}) (a2, a1); // Noncompliant }`, - errors: [ - { - message: `{"message":"Arguments 'a2' and 'a1' have the same names but not the same order as the function parameters.","secondaryLocations":[{"message":"Formal parameters","column":12,"line":6,"endColumn":24,"endLine":6}]}`, - line: 7, - endLine: 7, - column: 34, - endColumn: 40, - }, - ], - options: ['sonar-runtime'], - }, - invalid(` + errors: [ + { + message: `{"message":"Arguments 'a2' and 'a1' have the same names but not the same order as the function parameters.","secondaryLocations":[{"message":"Formal parameters","column":12,"line":6,"endColumn":24,"endLine":6}]}`, + line: 7, + endLine: 7, + column: 34, + endColumn: 40, + }, + ], + options: ['sonar-runtime'], + }, + invalid(` const from = 1, length = 2; const standardMethod = "str".substr(length, from); // Noncompliant `), - invalid(` + invalid(` export function sameType(a: Number, b: number, c = 3) {} const a = 1, c = 3, d = 4; const b: Number = 2; @@ -236,7 +237,7 @@ describe('S2234', () => { sameType(b, a); // Noncompliant sameType(42, c, b); // Noncompliant `), - invalid(` + invalid(` /** * @param a number * @param b string @@ -244,7 +245,7 @@ describe('S2234', () => { function withJsDoc(a, b){} withJsDoc(b, a); // Noncompliant `), - invalid(` + invalid(` class A { constructor(x: string, y: number, z = 42) {}; sameType(a: number, b: number, c = 3) {}; @@ -266,26 +267,27 @@ describe('S2234', () => { new A().sameType(42, c, b) // Noncompliant new A().differentTypes("hello", z, y); // Noncompliant `), - ], - }); + ], + }); - function invalid(code: string) { - const errors = []; - const lines = code.split('\n'); - for (let i = 1; i <= lines.length; i++) { - const line = lines[i - 1]; - if (line.includes('// Noncompliant')) { - errors.push({ - messageId: 'sonarRuntime', - line: i, - endLine: i, - }); + function invalid(code: string) { + const errors = []; + const lines = code.split('\n'); + for (let i = 1; i <= lines.length; i++) { + const line = lines[i - 1]; + if (line.includes('// Noncompliant')) { + errors.push({ + messageId: 'sonarRuntime', + line: i, + endLine: i, + }); + } } + return { + code: code, + errors, + options: ['sonar-runtime'], + }; } - return { - code: code, - errors, - options: ['sonar-runtime'], - }; - } + }); }); diff --git a/packages/jsts/src/rules/S2245/unit.test.ts b/packages/jsts/src/rules/S2245/unit.test.ts index e5a0f58b4f..1ae435378b 100644 --- a/packages/jsts/src/rules/S2245/unit.test.ts +++ b/packages/jsts/src/rules/S2245/unit.test.ts @@ -16,46 +16,48 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2245', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Using pseudorandom number generators (PRNGs) is security-sensitive', rule, { - valid: [ - { - code: `foo(x)`, - }, - { - code: `"Math.random()"`, - }, - { - code: `Math.foo()`, - }, - { - code: `Foo.random()`, - }, - ], - invalid: [ - { - code: `let x = Math.random();`, - errors: [ - { - message: 'Make sure that using this pseudorandom number generator is safe here.', - line: 1, - endLine: 1, - column: 9, - endColumn: 22, - }, - ], - }, - { - code: `foo(Math.random())`, - errors: 1, - }, - { - code: `let random = Math.random; foo(random());`, - errors: 1, - }, - ], + it('S2245', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Using pseudorandom number generators (PRNGs) is security-sensitive', rule, { + valid: [ + { + code: `foo(x)`, + }, + { + code: `"Math.random()"`, + }, + { + code: `Math.foo()`, + }, + { + code: `Foo.random()`, + }, + ], + invalid: [ + { + code: `let x = Math.random();`, + errors: [ + { + message: 'Make sure that using this pseudorandom number generator is safe here.', + line: 1, + endLine: 1, + column: 9, + endColumn: 22, + }, + ], + }, + { + code: `foo(Math.random())`, + errors: 1, + }, + { + code: `let random = Math.random; foo(random());`, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2251/unit.test.ts b/packages/jsts/src/rules/S2251/unit.test.ts index 4bc0998345..d7124fd2ba 100644 --- a/packages/jsts/src/rules/S2251/unit.test.ts +++ b/packages/jsts/src/rules/S2251/unit.test.ts @@ -16,265 +16,275 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2251', () => { - const ruleTesterJs = new RuleTester(); - const ruleTesterTs = new RuleTester(); + it('S2251', () => { + const ruleTesterJs = new RuleTester(); + const ruleTesterTs = new RuleTester(); - const testCases = { - valid: [ - { - code: ` + const testCases = { + valid: [ + { + code: ` for (let i = x; i < y; i++) {} `, - }, - { - code: ` + }, + { + code: ` for (i = x; i > y; i--) {} {} `, - }, - { - code: ` + }, + { + code: ` for (i = x; y > i; i++) {} {} `, - }, - { - code: ` + }, + { + code: ` for (i = x; y < i; i--) {} `, - }, - { - code: ` + }, + { + code: ` for (i = x; x < y; i--) {} `, - }, - { - code: ` + }, + { + code: ` for (i = x; x > y; i--) {} `, - }, - { - code: ` + }, + { + code: ` for (i = x; i > y; i-=1 ) {} `, - }, - { - code: ` + }, + { + code: ` for (i = x; i > y; i-=+1) {} `, - }, - { - code: ` + }, + { + code: ` for (i = x; i > y; i+=-x) {} `, - }, - { - code: ` + }, + { + code: ` for (i = x; i > y; i+=z ) {} `, - }, - { - code: ` + }, + { + code: ` for (i = x; i > y; i=i-1) {} `, - }, - { - code: ` + }, + { + code: ` for (i = x; i > y; i=i+z) {} `, - }, - { - code: ` + }, + { + code: ` for (i = x; i > y; i=z+1) {} `, - }, - { - code: ` + }, + { + code: ` for (i = x; i > y; i=i*2) {} `, - }, - { - code: ` + }, + { + code: ` for (i = x; i > y; i=i-z) {} `, - }, - { - code: ` + }, + { + code: ` for (i = x; i > y; object.x = i + 1) {} `, - }, - { - code: ` + }, + { + code: ` for (i = x; i+1 < y; i++) {} `, - }, - { - code: ` + }, + { + code: ` for (i = x; i < y; ) {} `, - }, - { - code: ` + }, + { + code: ` for (i = x; i > y; update()) {} `, - }, - { - code: ` + }, + { + code: ` for (i = x; condition(); i++) {} `, - }, - { - code: ` + }, + { + code: ` for (i = x; ; i++) {} `, - }, - { - code: ` + }, + { + code: ` for (i = x; i > y; i+=-1) {} `, - }, - { - code: ` + }, + { + code: ` for (i = x; i < y; i-=-1) {} `, - }, - { - code: ` + }, + { + code: ` for (i = ""; i<="aaa"; i+="a") {} `, - }, - { - code: ` + }, + { + code: ` for (let i = 0; i<=10; my_var.i++) {} `, - }, - { - code: ` + }, + { + code: ` for (let i = 0; i<=10; i=!i) {} `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` for (i = 0; i < 5; i--) {} // ^^^^^> ^^^ `, - errors: [ - { - message: `{"message":"\\"i\\" is decremented and will never reach its stop condition.","secondaryLocations":[{"column":24,"line":2,"endColumn":29,"endLine":2}]}`, - line: 2, - endLine: 2, - column: 32, - endColumn: 35, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: `{"message":"\\"i\\" is decremented and will never reach its stop condition.","secondaryLocations":[{"column":24,"line":2,"endColumn":29,"endLine":2}]}`, + line: 2, + endLine: 2, + column: 32, + endColumn: 35, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` for (let i = x; i > y; i++) {} // ^^^^^> ^^^ `, - errors: [ - { - message: `{"message":"\\"i\\" is incremented and will never reach its stop condition.","secondaryLocations":[{"column":28,"line":2,"endColumn":33,"endLine":2}]}`, - line: 2, - endLine: 2, - column: 36, - endColumn: 39, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: `{"message":"\\"i\\" is incremented and will never reach its stop condition.","secondaryLocations":[{"column":28,"line":2,"endColumn":33,"endLine":2}]}`, + line: 2, + endLine: 2, + column: 36, + endColumn: 39, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` for (let i = x; i >=y; i++) {} `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` for (let i = x; i < y; i--) {} `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` for (let i = x; i <=y; i--) {} `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` for (let i = x; y < i; i++) {} `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` for (let i = x; y <=i; i++) {} `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` for (let i = x; y > i; i--) {} `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` for (let i = x; y >=i; i--) {} `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` for (let i = x; y >i; i--) {} `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` for (i = x; i > y; i+=1 ) {} `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` for (i = x; i > y; i=i+1) {} `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` for (i = x; i > y; i=i+2) {} `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` for (i = x; i > y; i=i+1.) {} `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` for (i = x; i < y; i+=-1) {} `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` for (i = x; i > y; i-=-1) {} `, - errors: 1, - }, - ], - }; + errors: 1, + }, + ], + }; - ruleTesterJs.run('Loop increment should move in the right direction JavaScript', rule, testCases); - ruleTesterTs.run('Loop increment should move in the right direction TypeScript', rule, testCases); + ruleTesterJs.run( + 'Loop increment should move in the right direction JavaScript', + rule, + testCases, + ); + ruleTesterTs.run( + 'Loop increment should move in the right direction TypeScript', + rule, + testCases, + ); + }); }); diff --git a/packages/jsts/src/rules/S2255/unit.test.ts b/packages/jsts/src/rules/S2255/unit.test.ts index dc30a73456..8fa5e85f20 100644 --- a/packages/jsts/src/rules/S2255/unit.test.ts +++ b/packages/jsts/src/rules/S2255/unit.test.ts @@ -16,71 +16,73 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2255', () => { - const ruleTester = new RuleTester(); + it('S2255', () => { + const ruleTester = new RuleTester(); - ruleTester.run('Writing cookies is security-sensitive', rule, { - valid: [ - { - code: `document.foo`, - }, - { - code: `foo.cookie`, - }, - { - code: `response.setHeader()`, - }, - { - code: `response.setHeader('Content-Type', 'text/plain')`, - }, - { - code: `response.foo('Set-Cookie', x)`, - }, - { - code: `response.setHeader(SetCookie, x)`, - }, - { - code: `res.cookie("foo", "bar");`, - }, - { - code: `foo(req.cookies);`, - }, - { - code: `let x = document.cookie;`, - }, - { - code: `document.notCookie = 42`, - }, - { - code: `notDocument.cookie = 42`, - }, - { - code: `'express'; foo(req.cookies);`, - }, - ], - invalid: [ - { - code: `document.cookie = 42;`, - errors: [ - { - message: 'Make sure that cookie is written safely here.', - line: 1, - endLine: 1, - column: 1, - endColumn: 16, - }, - ], - }, - { - code: `response.setHeader('Set-Cookie', x);`, - errors: 1, - }, - { - code: `'express'; res.cookie("foo", "bar");`, - errors: 1, - }, - ], + ruleTester.run('Writing cookies is security-sensitive', rule, { + valid: [ + { + code: `document.foo`, + }, + { + code: `foo.cookie`, + }, + { + code: `response.setHeader()`, + }, + { + code: `response.setHeader('Content-Type', 'text/plain')`, + }, + { + code: `response.foo('Set-Cookie', x)`, + }, + { + code: `response.setHeader(SetCookie, x)`, + }, + { + code: `res.cookie("foo", "bar");`, + }, + { + code: `foo(req.cookies);`, + }, + { + code: `let x = document.cookie;`, + }, + { + code: `document.notCookie = 42`, + }, + { + code: `notDocument.cookie = 42`, + }, + { + code: `'express'; foo(req.cookies);`, + }, + ], + invalid: [ + { + code: `document.cookie = 42;`, + errors: [ + { + message: 'Make sure that cookie is written safely here.', + line: 1, + endLine: 1, + column: 1, + endColumn: 16, + }, + ], + }, + { + code: `response.setHeader('Set-Cookie', x);`, + errors: 1, + }, + { + code: `'express'; res.cookie("foo", "bar");`, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2259/unit.test.ts b/packages/jsts/src/rules/S2259/unit.test.ts index 244f944fb3..a54302a4e7 100644 --- a/packages/jsts/src/rules/S2259/unit.test.ts +++ b/packages/jsts/src/rules/S2259/unit.test.ts @@ -16,56 +16,57 @@ */ import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2259', () => { - const ruleTesterJsWithTypes = new RuleTester(); - const ruleTesterJs = new DefaultParserRuleTester(); + it('S2259', () => { + const ruleTesterJsWithTypes = new RuleTester(); + const ruleTesterJs = new DefaultParserRuleTester(); - ruleTesterJsWithTypes.run('', rule, { - valid: [ - { - code: ` + ruleTesterJsWithTypes.run('', rule, { + valid: [ + { + code: ` function builtin_property() { var str = "str"; str.trim(); // OK }`, - }, - { - code: ` + }, + { + code: ` function chained_properties() { var str = "str"; str.trim().trim(); // OK str.undefinedProperty.trim(); // OK, we don't know property "undefinedProperty" and consider it to have ANY_VALUE }`, - }, - { - code: ` + }, + { + code: ` function property_array() { var str = "str"; str.trim().split("t")[0]; // OK str.trim().undefinedArray[0]; // OK }`, - }, - { - code: ` + }, + { + code: ` function unknown() { var y; foo(y); y = foo(); y.foo; }`, - }, - { - code: ` + }, + { + code: ` function class_property() { class A { } A.foo = 42; }`, - }, - { - code: ` + }, + { + code: ` function branch() { var z; if (cond) { @@ -73,9 +74,9 @@ describe('S2259', () => { } z.foo(); // FN? }`, - }, - { - code: ` + }, + { + code: ` function foo() { if (some) { return 42;} } function equal_null() { var x = foo(); @@ -104,9 +105,9 @@ describe('S2259', () => { x.foo(); // FN } }`, - }, - { - code: ` + }, + { + code: ` function ternary() { var x; if (condition) { @@ -115,9 +116,9 @@ describe('S2259', () => { x ? x.foo() : bar(); // Compliant }`, - }, - { - code: ` + }, + { + code: ` function duplicated_condition() { if (foo("bar")) { var x = bar(); @@ -127,9 +128,9 @@ describe('S2259', () => { x.foo(); // OK } }`, - }, - { - code: ` + }, + { + code: ` function loop_at_least_once() { var x; @@ -139,9 +140,9 @@ describe('S2259', () => { x.foo(); }`, - }, - { - code: ` + }, + { + code: ` function loop(arr) { var obj; for(var i = 0; i < arr.length; i++){ @@ -152,9 +153,9 @@ describe('S2259', () => { } } }`, - }, - { - code: ` + }, + { + code: ` function one_condition() { var x = foo(); @@ -166,9 +167,9 @@ describe('S2259', () => { && x.foo != null) { // Ok } }`, - }, - { - code: ` + }, + { + code: ` function one_more() { var x = foo(); while (x != null && i < 10) { @@ -181,9 +182,9 @@ describe('S2259', () => { if (x.foo) { // Ok } }`, - }, - { - code: `function not_null_if_property_accessed() { + }, + { + code: `function not_null_if_property_accessed() { var x = foo(); if (x.foo) { @@ -192,9 +193,9 @@ describe('S2259', () => { x.foo(); // Ok } }`, - }, - { - code: ` + }, + { + code: ` function tested_copy() { var x; @@ -210,43 +211,43 @@ describe('S2259', () => { x.foo(); }`, - }, - { - code: `function assignment_left_first() { + }, + { + code: `function assignment_left_first() { var x; foo[x=foo()] = foo(x.bar); // Compliant, we first evaluate LHS of assignment }`, - }, - { - code: `function array_assignment() { + }, + { + code: `function array_assignment() { var x, y; x = 0; [x, y] = obj; x.foo; y.foo; }`, - }, - { - code: `function object_assignment() { + }, + { + code: `function object_assignment() { var x, y; x = 0; ({x, y} = obj); x.foo; y.foo; }`, - }, - { - code: `function object_assignment_with_named_properties() { + }, + { + code: `function object_assignment_with_named_properties() { var x, y; x = 0; ({prop1:x, prop2:y} = obj); x.foo; y.foo; }`, - }, - { - code: `function null_and_not_undefined() { + }, + { + code: `function null_and_not_undefined() { var x = null; while (condition()) { @@ -256,17 +257,17 @@ describe('S2259', () => { x.foo(); } }`, - }, - { - code: `function async_function_undefined() { + }, + { + code: `function async_function_undefined() { async function foo_implicit_return() { console.log("foo"); } // async function always return a Promise async function foo_return_undefined() { console.log("foo"); return undefined; } // async function always return a Promise foo_implicit_return().then(); // OK foo_return_undefined().then(); // OK }`, - }, - { - code: `function written_in_inner_fn() { + }, + { + code: `function written_in_inner_fn() { var x; function update_x() { x = 42 @@ -274,9 +275,9 @@ describe('S2259', () => { update_x() x.toString(); }`, - }, - { - code: ` + }, + { + code: ` var x; function update_x() { x = 42 @@ -284,65 +285,65 @@ describe('S2259', () => { update_x() x.toString(); `, - }, - { - code: ` + }, + { + code: ` function fn(ys) { var x; ys.forEach(function (y) { x = y; }) x.foo }`, - }, - { - code: ` + }, + { + code: ` var x; x?.foo; x?.y?.foo; x?.y?.z?.foo; `, - }, - { - code: ` + }, + { + code: ` if (x != null && x.prop == 0) {} if (x == null || x.prop == 0) {} if (x != undefined && x.prop == 0) {} if (x == undefined || x.prop == 0) {} `, - }, - { - code: `if (x == null && x?.prop == 0) {}`, - }, - { - code: `if (x == null && y.prop == 0) {}`, - }, - ], - invalid: [ - { - code: ` + }, + { + code: `if (x == null && x?.prop == 0) {}`, + }, + { + code: `if (x == null && y.prop == 0) {}`, + }, + ], + invalid: [ + { + code: ` function property() { var x; x.foo; //^ }`, - errors: [ - { - message: `TypeError can be thrown as "x" might be null or undefined here.`, - line: 4, - column: 9, - endColumn: 10, - }, - ], - }, - { - code: ` + errors: [ + { + message: `TypeError can be thrown as "x" might be null or undefined here.`, + line: 4, + column: 9, + endColumn: 10, + }, + ], + }, + { + code: ` function element() { var x; x[1]; }`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` function stop_after_NPE() { var x; var other_x; @@ -351,10 +352,10 @@ describe('S2259', () => { ) { } }`, - errors: 2, - }, - { - code: ` + errors: 2, + }, + { + code: ` function typeof_testing() { var x; @@ -376,18 +377,18 @@ describe('S2259', () => { y.call(); // Noncompliant } }`, - errors: [ - { - messageId: 'nullDereference', - line: 20, - endLine: 20, - column: 15, - endColumn: 16, - }, - ], - }, - { - code: `function one_issue_per_symbol() { + errors: [ + { + messageId: 'nullDereference', + line: 20, + endLine: 20, + column: 15, + endColumn: 16, + }, + ], + }, + { + code: `function one_issue_per_symbol() { var x; if (condition) { @@ -396,10 +397,10 @@ describe('S2259', () => { x.bar(); // no issue here as we already have issue for same symbol } }`, - errors: 1, - }, - { - code: `function for_of_undefined() { + errors: 1, + }, + { + code: `function for_of_undefined() { var undefinedArray; for(let i of undefinedArray) { // Noncompliant } @@ -416,78 +417,79 @@ describe('S2259', () => { for(x of obj) { // OK we should not care about x being undefined } }`, - errors: [ - { - messageId: 'nullDereference', - line: 3, - endLine: 3, - column: 22, - endColumn: 36, - }, - { - messageId: 'nullDereference', - line: 7, - endLine: 7, - column: 22, - endColumn: 31, - }, - ], - }, - { - code: ` + errors: [ + { + messageId: 'nullDereference', + line: 3, + endLine: 3, + column: 22, + endColumn: 36, + }, + { + messageId: 'nullDereference', + line: 7, + endLine: 7, + column: 22, + endColumn: 31, + }, + ], + }, + { + code: ` var x; x.foo`, - errors: 1, - }, - { - code: `if (x == null && x.prop == 0) {}`, - errors: [ - { - messageId: 'shortCircuitError', - }, - ], - }, - { - code: `if (null != x || x.prop == 0) {}`, - errors: [ - { - messageId: 'shortCircuitError', - }, - ], - }, - { - code: `if (undefined == x && x.prop == 0) {}`, - errors: [ - { - messageId: 'shortCircuitError', - }, - ], - }, - { - code: `if (x.prop != undefined || x.prop.prop2 == 0) {}`, - errors: [ - { - line: 1, - endLine: 1, - column: 28, - endColumn: 34, - messageId: 'shortCircuitError', - }, - ], - }, - ], - }); + errors: 1, + }, + { + code: `if (x == null && x.prop == 0) {}`, + errors: [ + { + messageId: 'shortCircuitError', + }, + ], + }, + { + code: `if (null != x || x.prop == 0) {}`, + errors: [ + { + messageId: 'shortCircuitError', + }, + ], + }, + { + code: `if (undefined == x && x.prop == 0) {}`, + errors: [ + { + messageId: 'shortCircuitError', + }, + ], + }, + { + code: `if (x.prop != undefined || x.prop.prop2 == 0) {}`, + errors: [ + { + line: 1, + endLine: 1, + column: 28, + endColumn: 34, + messageId: 'shortCircuitError', + }, + ], + }, + ], + }); - ruleTesterJs.run('', rule, { - valid: [ - { - code: ` + ruleTesterJs.run('', rule, { + valid: [ + { + code: ` function property() { var x; x.foo; // OK, no type information available }`, - }, - ], - invalid: [], + }, + ], + invalid: [], + }); }); }); diff --git a/packages/jsts/src/rules/S2301/unit.test.ts b/packages/jsts/src/rules/S2301/unit.test.ts index 71650c0e70..6246586d46 100644 --- a/packages/jsts/src/rules/S2301/unit.test.ts +++ b/packages/jsts/src/rules/S2301/unit.test.ts @@ -16,16 +16,17 @@ */ import { rule as S2301 } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2301', () => { - const ruleTester = new RuleTester(); - - ruleTester.run('S2301:TypeScript', S2301, { - invalid: [ - { - name: 'RSPEC non-compliant code example', - code: `function tempt1(name: string, ofAge: boolean) { + it('S2301', () => { + const ruleTester = new RuleTester(); + + ruleTester.run('S2301:TypeScript', S2301, { + invalid: [ + { + name: 'RSPEC non-compliant code example', + code: `function tempt1(name: string, ofAge: boolean) { if (ofAge) { offerLiquor(name); } else { @@ -41,85 +42,85 @@ function tempt3(name: string, ofAge: boolean) { return ofAge ? offerLiquor(name) : offerCandy(name); } `, - options: ['sonar-runtime'], - errors: [ - { - line: 2, - column: 7, - endLine: 2, - endColumn: 12, - messageId: 'sonarRuntime', - data: { - parameterName: 'foo', - sonarRuntimeData: JSON.stringify({ - message: - 'Provide multiple methods instead of using "ofAge" to determine which action to take.', - secondaryLocations: [ - { - message: 'Parameter "ofAge" was declared here', - column: 30, - line: 1, - endColumn: 44, - endLine: 1, - }, - ], - }), + options: ['sonar-runtime'], + errors: [ + { + line: 2, + column: 7, + endLine: 2, + endColumn: 12, + messageId: 'sonarRuntime', + data: { + parameterName: 'foo', + sonarRuntimeData: JSON.stringify({ + message: + 'Provide multiple methods instead of using "ofAge" to determine which action to take.', + secondaryLocations: [ + { + message: 'Parameter "ofAge" was declared here', + column: 30, + line: 1, + endColumn: 44, + endLine: 1, + }, + ], + }), + }, }, - }, - { - line: 10, - column: 3, - endLine: 10, - endColumn: 8, - messageId: 'sonarRuntime', - data: { - parameterName: 'foo', - sonarRuntimeData: JSON.stringify({ - message: - 'Provide multiple methods instead of using "ofAge" to determine which action to take.', - secondaryLocations: [ - { - message: 'Parameter "ofAge" was declared here', - column: 30, - line: 9, - endColumn: 44, - endLine: 9, - }, - ], - }), + { + line: 10, + column: 3, + endLine: 10, + endColumn: 8, + messageId: 'sonarRuntime', + data: { + parameterName: 'foo', + sonarRuntimeData: JSON.stringify({ + message: + 'Provide multiple methods instead of using "ofAge" to determine which action to take.', + secondaryLocations: [ + { + message: 'Parameter "ofAge" was declared here', + column: 30, + line: 9, + endColumn: 44, + endLine: 9, + }, + ], + }), + }, }, - }, - { - line: 14, - column: 10, - endLine: 14, - endColumn: 15, - messageId: 'sonarRuntime', - data: { - parameterName: 'foo', - sonarRuntimeData: JSON.stringify({ - message: - 'Provide multiple methods instead of using "ofAge" to determine which action to take.', - secondaryLocations: [ - { - message: 'Parameter "ofAge" was declared here', - column: 30, - line: 13, - endColumn: 44, - endLine: 13, - }, - ], - }), + { + line: 14, + column: 10, + endLine: 14, + endColumn: 15, + messageId: 'sonarRuntime', + data: { + parameterName: 'foo', + sonarRuntimeData: JSON.stringify({ + message: + 'Provide multiple methods instead of using "ofAge" to determine which action to take.', + secondaryLocations: [ + { + message: 'Parameter "ofAge" was declared here', + column: 30, + line: 13, + endColumn: 44, + endLine: 13, + }, + ], + }), + }, }, - }, - ], - }, - ], - valid: [ - { - name: `RSPEC compliant code example`, - options: ['sonar-runtime'], - code: `function temptAdult(name: string) { + ], + }, + ], + valid: [ + { + name: `RSPEC compliant code example`, + options: ['sonar-runtime'], + code: `function temptAdult(name: string) { offerLiquor(name); } @@ -183,19 +184,19 @@ function tempt8(name: string, ofAge: boolean) { } } `, - }, - ], - }); - - const javaScriptRuleTester = new RuleTester(); - - javaScriptRuleTester.run('S2301:JavaScript', S2301, { - invalid: [], - valid: [ - { - name: `RSPEC compliant code example`, - options: ['sonar-runtime'], - code: `function temptAdult(name) { + }, + ], + }); + + const javaScriptRuleTester = new RuleTester(); + + javaScriptRuleTester.run('S2301:JavaScript', S2301, { + invalid: [], + valid: [ + { + name: `RSPEC compliant code example`, + options: ['sonar-runtime'], + code: `function temptAdult(name) { offerLiquor(name); } @@ -269,7 +270,8 @@ function tempt10(name, ofAge) { return ofAge ? offerLiquor(name) : offerCandy(name); } `, - }, - ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2310/unit.test.ts b/packages/jsts/src/rules/S2310/unit.test.ts index 60129f2af0..316f2fb411 100644 --- a/packages/jsts/src/rules/S2310/unit.test.ts +++ b/packages/jsts/src/rules/S2310/unit.test.ts @@ -16,14 +16,15 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2310', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Loop counter should not be updated inside loop', rule, { - valid: [ - { - code: ` + it('S2310', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Loop counter should not be updated inside loop', rule, { + valid: [ + { + code: ` let fl = false; for (; i < m && !fl; i++) { @@ -31,46 +32,46 @@ describe('S2310', () => { m = 10; // Compliant } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` for (var i = 0, j = 2; i < 5; i++) { i = 5; // Noncompliant j = 5; // compliant, not in update section } `, - errors: [ - { - line: 3, - column: 11, - endColumn: 12, - message: `{"message":"Remove this assignment of \\"i\\".","secondaryLocations":[{"message":"Counter variable update","column":38,"line":2,"endColumn":39,"endLine":2}]}`, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + line: 3, + column: 11, + endColumn: 12, + message: `{"message":"Remove this assignment of \\"i\\".","secondaryLocations":[{"message":"Counter variable update","column":38,"line":2,"endColumn":39,"endLine":2}]}`, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` for (var i; i < 5; i++) { i = 5; // Noncompliant } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` var i; i = 0; for (; i < 5; i++) { i = 5; // Noncompliant } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` var k, t, l, m; for (k = 0, t = 6, l = 2; k < 5; k++) { k = 5; // Noncompliant @@ -81,29 +82,29 @@ describe('S2310', () => { m = 5; // Noncompliant } `, - errors: [ - { message: 'Remove this assignment of "k".', line: 4 }, - { message: 'Remove this assignment of "m".', line: 9 }, - ], - }, - { - code: ` + errors: [ + { message: 'Remove this assignment of "k".', line: 4 }, + { message: 'Remove this assignment of "m".', line: 9 }, + ], + }, + { + code: ` var x = 5; for (x += 2; x < 5; x++) { x = 5; // Noncompliant } `, - errors: [ - { - line: 5, - message: `{"message":"Remove this assignment of \\"x\\".","secondaryLocations":[{"message":"Counter variable update","column":28,"line":4,"endColumn":29,"endLine":4}]}`, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + line: 5, + message: `{"message":"Remove this assignment of \\"x\\".","secondaryLocations":[{"message":"Counter variable update","column":28,"line":4,"endColumn":29,"endLine":4}]}`, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` let i = 0, j = 0, k = 0; for (;; i++, --j) { i++; // Noncompliant @@ -122,18 +123,18 @@ describe('S2310', () => { k++; // Noncompliant } `, - errors: 8, - }, - { - code: ` + errors: 8, + }, + { + code: ` for (var x = foo(); ; x=next()) { x = next(); // Noncompliant } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` function foo_of_loop(obj) { for (var prop1 of obj) { prop1 = 1 // Noncompliant @@ -150,10 +151,10 @@ describe('S2310', () => { } `, - errors: 3, - }, - { - code: ` + errors: 3, + }, + { + code: ` function foo_in_loop(obj) { for (var value1 in obj) { value1 = 1 // Noncompliant @@ -169,10 +170,10 @@ describe('S2310', () => { } } `, - errors: 3, - }, - { - code: ` + errors: 3, + }, + { + code: ` function description_sample_code() { var names = [ "Jack", "Jim", "", "John" ]; for (var i = 0; i < names.length; i++) { @@ -195,10 +196,10 @@ describe('S2310', () => { } `, - errors: [{ message: 'Remove this assignment of "i".', line: 6 }], - }, - { - code: ` + errors: [{ message: 'Remove this assignment of "i".', line: 6 }], + }, + { + code: ` function same_counter_in_nested_loop(obj1, obj2) { for (var i in obj1) { for (i of obj2) { // Noncompliant @@ -207,10 +208,10 @@ describe('S2310', () => { } } `, - errors: [{ message: 'Remove this assignment of "i".', line: 4 }], - }, - { - code: ` + errors: [{ message: 'Remove this assignment of "i".', line: 4 }], + }, + { + code: ` function assigned_several_times(obj) { for (var value in obj) { value = 1; // Noncompliant @@ -219,10 +220,10 @@ describe('S2310', () => { } `, - errors: 2, - }, - { - code: ` + errors: 2, + }, + { + code: ` function used_several_times(obj) { for (var i = 0; i < 10; i++) { for (var j = 0; j < 10; j++, i++) { // Noncompliant @@ -231,25 +232,26 @@ describe('S2310', () => { } } `, - errors: [ - { - line: 4, - column: 40, - message: `{"message":"Remove this assignment of \\"i\\".","secondaryLocations":[{"message":"Counter variable update","column":32,"line":3,"endColumn":33,"endLine":3}]}`, - }, - { - line: 5, - column: 13, - message: `{"message":"Remove this assignment of \\"i\\".","secondaryLocations":[{"message":"Counter variable update","column":32,"line":3,"endColumn":33,"endLine":3}]}`, - }, - { - line: 5, - column: 13, - message: `{"message":"Remove this assignment of \\"i\\".","secondaryLocations":[{"message":"Counter variable update","column":39,"line":4,"endColumn":40,"endLine":4}]}`, - }, - ], - options: ['sonar-runtime'], - }, - ], + errors: [ + { + line: 4, + column: 40, + message: `{"message":"Remove this assignment of \\"i\\".","secondaryLocations":[{"message":"Counter variable update","column":32,"line":3,"endColumn":33,"endLine":3}]}`, + }, + { + line: 5, + column: 13, + message: `{"message":"Remove this assignment of \\"i\\".","secondaryLocations":[{"message":"Counter variable update","column":32,"line":3,"endColumn":33,"endLine":3}]}`, + }, + { + line: 5, + column: 13, + message: `{"message":"Remove this assignment of \\"i\\".","secondaryLocations":[{"message":"Counter variable update","column":39,"line":4,"endColumn":40,"endLine":4}]}`, + }, + ], + options: ['sonar-runtime'], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2376/unit.test.ts b/packages/jsts/src/rules/S2376/unit.test.ts index 072ecc0471..5bc05acf98 100644 --- a/packages/jsts/src/rules/S2376/unit.test.ts +++ b/packages/jsts/src/rules/S2376/unit.test.ts @@ -16,68 +16,70 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2376', () => { - const ruleTester = new RuleTester(); + it('S2376', () => { + const ruleTester = new RuleTester(); - ruleTester.run(`Property getters and setters should come in pairs`, rule, { - valid: [ - { - code: ` + ruleTester.run(`Property getters and setters should come in pairs`, rule, { + valid: [ + { + code: ` class C { get m() { return this.a; } set m(a) { this.a = a; } }`, - }, - { - code: ` + }, + { + code: ` class C { @Input() set m(a) { this.a = a; } }`, - }, - { - code: ` + }, + { + code: ` class C { get m() { return this.a; } set m(a) { this.a = a; } }`, - options: [{ getWithoutSet: true }], - }, - ], - invalid: [ - { - code: ` + options: [{ getWithoutSet: true }], + }, + ], + invalid: [ + { + code: ` class C { set m(a) { this.a = a; } }`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` class C { @Input set m(a) { this.a = a; } }`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` class C { @NonAngularInput() set m(a) { this.a = a; } }`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` class C { get m() { return this.a; } }`, - options: [{ getWithoutSet: true }], - errors: 1, - }, - ], + options: [{ getWithoutSet: true }], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2392/unit.test.ts b/packages/jsts/src/rules/S2392/unit.test.ts index 4d74f2afe2..7beb685817 100644 --- a/packages/jsts/src/rules/S2392/unit.test.ts +++ b/packages/jsts/src/rules/S2392/unit.test.ts @@ -16,14 +16,15 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2392', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Variables should be used in the blocks where they are declared', rule, { - valid: [ - { - code: ` + it('S2392', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Variables should be used in the blocks where they are declared', rule, { + valid: [ + { + code: ` function fun() { if (cond) { @@ -50,11 +51,11 @@ describe('S2392', () => { } } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function fun() { if (cond) { var a = 42; @@ -64,19 +65,19 @@ describe('S2392', () => { } } `, - errors: [ - { - message: `{"message":"Consider moving declaration of 'a' as it is referenced outside current binding context.","secondaryLocations":[{"message":"Outside reference.","column":16,"line":7,"endColumn":17,"endLine":7}]}`, - line: 4, - endLine: 4, - column: 17, - endColumn: 18, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: `{"message":"Consider moving declaration of 'a' as it is referenced outside current binding context.","secondaryLocations":[{"message":"Outside reference.","column":16,"line":7,"endColumn":17,"endLine":7}]}`, + line: 4, + endLine: 4, + column: 17, + endColumn: 18, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` function fun() { if (cond) { var a = 42; // nok @@ -84,35 +85,35 @@ describe('S2392', () => { console.log(a); } `, - errors: [ - { - message: `{"message":"Consider moving declaration of 'a' as it is referenced outside current binding context.","secondaryLocations":[{"message":"Outside reference.","column":20,"line":6,"endColumn":21,"endLine":6}]}`, - line: 4, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: `{"message":"Consider moving declaration of 'a' as it is referenced outside current binding context.","secondaryLocations":[{"message":"Outside reference.","column":20,"line":6,"endColumn":21,"endLine":6}]}`, + line: 4, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` function fun() { for (var i = 0; ;) {} foo(i); return i; } `, - errors: [ - { - message: `{"message":"Consider moving declaration of 'i' as it is referenced outside current binding context.","secondaryLocations":[{"message":"Outside reference.","column":14,"line":4,"endColumn":15,"endLine":4},{"message":"Outside reference.","column":17,"line":5,"endColumn":18,"endLine":5}]}`, - line: 3, - endLine: 3, - column: 20, - endColumn: 21, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: `{"message":"Consider moving declaration of 'i' as it is referenced outside current binding context.","secondaryLocations":[{"message":"Outside reference.","column":14,"line":4,"endColumn":15,"endLine":4},{"message":"Outside reference.","column":17,"line":5,"endColumn":18,"endLine":5}]}`, + line: 3, + endLine: 3, + column: 20, + endColumn: 21, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` function fun() { for (var i in smth) {} foo(i); @@ -127,24 +128,25 @@ describe('S2392', () => { foo(k); } `, - errors: [ - { - message: - "Consider moving declaration of 'i' as it is referenced outside current binding context.", - line: 3, - }, - { - message: - "Consider moving declaration of 'j' as it is referenced outside current binding context.", - line: 6, - }, - { - message: - "Consider moving declaration of 'k' as it is referenced outside current binding context.", - line: 11, - }, - ], - }, - ], + errors: [ + { + message: + "Consider moving declaration of 'i' as it is referenced outside current binding context.", + line: 3, + }, + { + message: + "Consider moving declaration of 'j' as it is referenced outside current binding context.", + line: 6, + }, + { + message: + "Consider moving declaration of 'k' as it is referenced outside current binding context.", + line: 11, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2424/unit.test.ts b/packages/jsts/src/rules/S2424/unit.test.ts index b6851cf542..a0ecc98610 100644 --- a/packages/jsts/src/rules/S2424/unit.test.ts +++ b/packages/jsts/src/rules/S2424/unit.test.ts @@ -16,68 +16,70 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2424', () => { - const tests = { - valid: [ - { - code: `new Promise();`, - }, - { - code: `var obj = new Object();`, - }, - { - code: `var System = 2`, - }, - ], - invalid: [ - { - code: `var JSON = 5;`, - errors: [ - { - message: 'Remove this override of "JSON".', - line: 1, - endLine: 1, - column: 5, - endColumn: 9, - }, - ], - }, - { - code: `Set = "str";`, - errors: 1, - }, - { - code: `for (Math in arr) {};`, - errors: 1, - }, - { - code: `function fun(Reflect) {};`, - errors: 1, - }, - { - code: `JSON++;`, - errors: 1, - }, - { - code: `function Date() {}`, - errors: 1, - }, - ], - }; + it('S2424', () => { + const tests = { + valid: [ + { + code: `new Promise();`, + }, + { + code: `var obj = new Object();`, + }, + { + code: `var System = 2`, + }, + ], + invalid: [ + { + code: `var JSON = 5;`, + errors: [ + { + message: 'Remove this override of "JSON".', + line: 1, + endLine: 1, + column: 5, + endColumn: 9, + }, + ], + }, + { + code: `Set = "str";`, + errors: 1, + }, + { + code: `for (Math in arr) {};`, + errors: 1, + }, + { + code: `function fun(Reflect) {};`, + errors: 1, + }, + { + code: `JSON++;`, + errors: 1, + }, + { + code: `function Date() {}`, + errors: 1, + }, + ], + }; - const ruleTesterJs = new RuleTester(); - ruleTesterJs.run('Built-in objects should not be overridden [js]', rule, tests); + const ruleTesterJs = new RuleTester(); + ruleTesterJs.run('Built-in objects should not be overridden [js]', rule, tests); - tests.valid.push({ - code: ` + tests.valid.push({ + code: ` enum Result { Error, Success }`, - }); + }); - const ruleTesterTs = new RuleTester(); - ruleTesterTs.run('Built-in objects should not be overridden [ts]', rule, tests); + const ruleTesterTs = new RuleTester(); + ruleTesterTs.run('Built-in objects should not be overridden [ts]', rule, tests); + }); }); diff --git a/packages/jsts/src/rules/S2428/unit.test.ts b/packages/jsts/src/rules/S2428/unit.test.ts index 80f598f583..72f44da7d5 100644 --- a/packages/jsts/src/rules/S2428/unit.test.ts +++ b/packages/jsts/src/rules/S2428/unit.test.ts @@ -16,52 +16,53 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2428', () => { - const ruleTester = new RuleTester(); + it('S2428', () => { + const ruleTester = new RuleTester(); - ruleTester.run('prefer-literal', rule, { - valid: [ - { - code: `var x = {a: 2}`, - }, - { - code: ` + ruleTester.run('prefer-literal', rule, { + valid: [ + { + code: `var x = {a: 2}`, + }, + { + code: ` function Foo(a) { this.a = a; }; var x = new Foo(2);`, - }, - { - code: ` + }, + { + code: ` var x = {a: 2}; y = "foo";`, - }, - // FN - { - code: ` + }, + // FN + { + code: ` var x; x = {}; x.a = 2`, - }, - // FN - { - code: `var x = {a: 2}; doSomething(); x.b = 3;`, - }, - { - code: ` + }, + // FN + { + code: `var x = {a: 2}; doSomething(); x.b = 3;`, + }, + { + code: ` function foo() { var x = {a: 2}; doSomething(); }`, - }, - { - code: `var x = {}; x["a"] = 2;`, - }, - // No issue on multiline expressions, may be done for readability - { - code: ` + }, + { + code: `var x = {}; x["a"] = 2;`, + }, + // No issue on multiline expressions, may be done for readability + { + code: ` var x = {}; x.foo = function () { doSomething(); @@ -71,120 +72,121 @@ describe('S2428', () => { a: 1, b: 2 }`, - }, - // OK, report only when empty object - { - code: `var x = {a: 2}; x.b = 5;`, - }, - { - code: ` + }, + // OK, report only when empty object + { + code: `var x = {a: 2}; x.b = 5;`, + }, + { + code: ` const O = {}; O.self = O;`, - }, - ], - invalid: [ - { - code: `var x = {}; x.a = 2;`, - errors: [ - { - messageId: 'declarePropertiesInsideObject', - line: 1, - endLine: 1, - column: 5, - endColumn: 11, - }, - ], - }, - { - code: ` + }, + ], + invalid: [ + { + code: `var x = {}; x.a = 2;`, + errors: [ + { + messageId: 'declarePropertiesInsideObject', + line: 1, + endLine: 1, + column: 5, + endColumn: 11, + }, + ], + }, + { + code: ` var x = {}, y = "hello"; x.a = 2;`, - errors: [ - { - messageId: 'declarePropertiesInsideObject', - line: 2, - endLine: 2, - column: 13, - endColumn: 19, - }, - ], - }, - { - code: `var x = {}; x.a = 2; x.b = 3`, - errors: [ - { - messageId: 'declarePropertiesInsideObject', - line: 1, - endLine: 1, - column: 5, - endColumn: 11, - }, - ], - }, - { - code: `let x = {}; x.a = 2;`, - errors: [ - { - messageId: 'declarePropertiesInsideObject', - line: 1, - endLine: 1, - column: 5, - endColumn: 11, - }, - ], - }, - { - code: `const x = {}; x.a = 2;`, - errors: [ - { - messageId: 'declarePropertiesInsideObject', - line: 1, - endLine: 1, - column: 7, - endColumn: 13, - }, - ], - }, - { - code: `{ var x = {}; x.a = 2; }`, - errors: [ - { - messageId: 'declarePropertiesInsideObject', - line: 1, - endLine: 1, - column: 7, - endColumn: 13, - }, - ], - }, - { - code: `if (a) { var x = {}; x.a = 2; }`, - errors: [ - { - messageId: 'declarePropertiesInsideObject', - line: 1, - endLine: 1, - column: 14, - endColumn: 20, - }, - ], - }, - { - code: `function foo() { + errors: [ + { + messageId: 'declarePropertiesInsideObject', + line: 2, + endLine: 2, + column: 13, + endColumn: 19, + }, + ], + }, + { + code: `var x = {}; x.a = 2; x.b = 3`, + errors: [ + { + messageId: 'declarePropertiesInsideObject', + line: 1, + endLine: 1, + column: 5, + endColumn: 11, + }, + ], + }, + { + code: `let x = {}; x.a = 2;`, + errors: [ + { + messageId: 'declarePropertiesInsideObject', + line: 1, + endLine: 1, + column: 5, + endColumn: 11, + }, + ], + }, + { + code: `const x = {}; x.a = 2;`, + errors: [ + { + messageId: 'declarePropertiesInsideObject', + line: 1, + endLine: 1, + column: 7, + endColumn: 13, + }, + ], + }, + { + code: `{ var x = {}; x.a = 2; }`, + errors: [ + { + messageId: 'declarePropertiesInsideObject', + line: 1, + endLine: 1, + column: 7, + endColumn: 13, + }, + ], + }, + { + code: `if (a) { var x = {}; x.a = 2; }`, + errors: [ + { + messageId: 'declarePropertiesInsideObject', + line: 1, + endLine: 1, + column: 14, + endColumn: 20, + }, + ], + }, + { + code: `function foo() { var x = {}; x.a = 2; }`, - errors: [ - { - messageId: 'declarePropertiesInsideObject', - line: 2, - endLine: 2, - column: 13, - endColumn: 19, - }, - ], - }, - ], + errors: [ + { + messageId: 'declarePropertiesInsideObject', + line: 2, + endLine: 2, + column: 13, + endColumn: 19, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2430/unit.test.ts b/packages/jsts/src/rules/S2430/unit.test.ts index cedbbaa01e..d4aba6455f 100644 --- a/packages/jsts/src/rules/S2430/unit.test.ts +++ b/packages/jsts/src/rules/S2430/unit.test.ts @@ -16,38 +16,40 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2430', () => { - const ruleTester = new RuleTester(); + it('S2430', () => { + const ruleTester = new RuleTester(); - ruleTester.run(`A constructor name should not start with a lowercase letter`, rule, { - valid: [ - { - code: `let x = new Thing();`, - }, - { - code: ` + ruleTester.run(`A constructor name should not start with a lowercase letter`, rule, { + valid: [ + { + code: `let x = new Thing();`, + }, + { + code: ` let ctor = condition ? Foo : Bar; let item = new ctor(); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function thing(){} let x = new thing(); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` let obj = condition ? {ctor: Foo} : {ctor: Bar}; let item = new obj.ctor(); `, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2589/unit.test.ts b/packages/jsts/src/rules/S2589/unit.test.ts index 7c3410bbc4..b85f69f0af 100644 --- a/packages/jsts/src/rules/S2589/unit.test.ts +++ b/packages/jsts/src/rules/S2589/unit.test.ts @@ -16,28 +16,29 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2589', () => { - const ruleTester = new RuleTester(); + it('S2589', () => { + const ruleTester = new RuleTester(); - const falsySonarRuntimeData = JSON.stringify({ - message: 'This always evaluates to falsy. Consider refactoring this code.', - secondaryLocations: [ - { message: 'Evaluated here to be falsy', column: 12, line: 3, endColumn: 13, endLine: 3 }, - ], - }); - const truthySonarRuntimeData = JSON.stringify({ - message: 'This always evaluates to truthy. Consider refactoring this code.', - secondaryLocations: [ - { message: 'Evaluated here to be truthy', column: 12, line: 3, endColumn: 13, endLine: 3 }, - ], - }); + const falsySonarRuntimeData = JSON.stringify({ + message: 'This always evaluates to falsy. Consider refactoring this code.', + secondaryLocations: [ + { message: 'Evaluated here to be falsy', column: 12, line: 3, endColumn: 13, endLine: 3 }, + ], + }); + const truthySonarRuntimeData = JSON.stringify({ + message: 'This always evaluates to truthy. Consider refactoring this code.', + secondaryLocations: [ + { message: 'Evaluated here to be truthy', column: 12, line: 3, endColumn: 13, endLine: 3 }, + ], + }); - ruleTester.run('no-gratuitous-expressions', rule, { - valid: [ - { - code: ` + ruleTester.run('no-gratuitous-expressions', rule, { + valid: [ + { + code: ` function bar(x: boolean) { if (x && y) { } else { @@ -45,9 +46,9 @@ describe('S2589', () => { } } `, - }, - { - code: ` + }, + { + code: ` function bar(x: boolean) { if (x) { x = bar(); @@ -55,9 +56,9 @@ describe('S2589', () => { } } `, - }, - { - code: ` + }, + { + code: ` function bar(x: boolean) { if (x) { while (cond) { @@ -67,9 +68,9 @@ describe('S2589', () => { } } `, - }, - { - code: ` + }, + { + code: ` function bar(x: boolean) { if (x) { nested(); @@ -81,9 +82,9 @@ describe('S2589', () => { } } `, - }, - { - code: ` + }, + { + code: ` function render(children, right) { if (children) { return ( @@ -94,109 +95,109 @@ describe('S2589', () => { } } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` if (true) {} if (false) {}`, - options: ['sonar-runtime'], - errors: [ - { - messageId: 'sonarRuntime', - data: { - value: 'truthy', - sonarRuntimeData: JSON.stringify({ - message: 'This always evaluates to truthy. Consider refactoring this code.', - secondaryLocations: [], - }), + options: ['sonar-runtime'], + errors: [ + { + messageId: 'sonarRuntime', + data: { + value: 'truthy', + sonarRuntimeData: JSON.stringify({ + message: 'This always evaluates to truthy. Consider refactoring this code.', + secondaryLocations: [], + }), + }, + line: 2, }, - line: 2, - }, - { - messageId: 'sonarRuntime', - data: { - value: 'falsy', - sonarRuntimeData: JSON.stringify({ - message: 'This always evaluates to falsy. Consider refactoring this code.', - secondaryLocations: [], - }), + { + messageId: 'sonarRuntime', + data: { + value: 'falsy', + sonarRuntimeData: JSON.stringify({ + message: 'This always evaluates to falsy. Consider refactoring this code.', + secondaryLocations: [], + }), + }, + line: 3, }, - line: 3, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` function bar(x: boolean, z) { if (x && z) { if (y && x) {} // "x" always true if (y && z) {} // "z" always true } }`, - options: ['sonar-runtime'], - errors: [ - { - messageId: 'sonarRuntime', - data: { - value: 'truthy', - sonarRuntimeData: truthySonarRuntimeData, + options: ['sonar-runtime'], + errors: [ + { + messageId: 'sonarRuntime', + data: { + value: 'truthy', + sonarRuntimeData: truthySonarRuntimeData, + }, + line: 4, + column: 20, + endLine: 4, + endColumn: 21, }, - line: 4, - column: 20, - endLine: 4, - endColumn: 21, - }, - { - messageId: 'sonarRuntime', - data: { - value: 'truthy', - sonarRuntimeData: JSON.stringify({ - message: 'This always evaluates to truthy. Consider refactoring this code.', - secondaryLocations: [ - { - message: 'Evaluated here to be truthy', - column: 17, - line: 3, - endColumn: 18, - endLine: 3, - }, - ], - }), + { + messageId: 'sonarRuntime', + data: { + value: 'truthy', + sonarRuntimeData: JSON.stringify({ + message: 'This always evaluates to truthy. Consider refactoring this code.', + secondaryLocations: [ + { + message: 'Evaluated here to be truthy', + column: 17, + line: 3, + endColumn: 18, + endLine: 3, + }, + ], + }), + }, + line: 5, + column: 20, + endLine: 5, + endColumn: 21, }, - line: 5, - column: 20, - endLine: 5, - endColumn: 21, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` function bar(x: boolean) { if (x) { if (x) { // "x" always true } } }`, - options: ['sonar-runtime'], - errors: [ - { - messageId: 'sonarRuntime', - data: { - value: 'truthy', - sonarRuntimeData: truthySonarRuntimeData, + options: ['sonar-runtime'], + errors: [ + { + messageId: 'sonarRuntime', + data: { + value: 'truthy', + sonarRuntimeData: truthySonarRuntimeData, + }, + line: 4, + column: 15, + endLine: 4, + endColumn: 16, }, - line: 4, - column: 15, - endLine: 4, - endColumn: 16, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` function bar(x: boolean ) { x++; if (x) { @@ -205,90 +206,90 @@ describe('S2589', () => { } x = foo(); }`, - options: ['sonar-runtime'], - errors: [ - { - messageId: 'sonarRuntime', - data: { - value: 'truthy', - sonarRuntimeData: JSON.stringify({ - message: 'This always evaluates to truthy. Consider refactoring this code.', - secondaryLocations: [ - { - message: 'Evaluated here to be truthy', - column: 12, - line: 4, - endColumn: 13, - endLine: 4, - }, - ], - }), + options: ['sonar-runtime'], + errors: [ + { + messageId: 'sonarRuntime', + data: { + value: 'truthy', + sonarRuntimeData: JSON.stringify({ + message: 'This always evaluates to truthy. Consider refactoring this code.', + secondaryLocations: [ + { + message: 'Evaluated here to be truthy', + column: 12, + line: 4, + endColumn: 13, + endLine: 4, + }, + ], + }), + }, + line: 5, + column: 15, + endLine: 5, + endColumn: 16, }, - line: 5, - column: 15, - endLine: 5, - endColumn: 16, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` function bar(x: boolean) { if (x) { if (!x) { // Noncompliant } } }`, - options: ['sonar-runtime'], - errors: [ - { - messageId: 'sonarRuntime', - data: { - value: 'truthy', - sonarRuntimeData: truthySonarRuntimeData, + options: ['sonar-runtime'], + errors: [ + { + messageId: 'sonarRuntime', + data: { + value: 'truthy', + sonarRuntimeData: truthySonarRuntimeData, + }, + line: 4, + column: 16, + endLine: 4, + endColumn: 17, }, - line: 4, - column: 16, - endLine: 4, - endColumn: 17, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` function bar(x: boolean) { if (!x) { foo(!x) // Noncompliant } }`, - options: ['sonar-runtime'], - errors: [ - { - messageId: 'sonarRuntime', - data: { - value: 'falsy', - sonarRuntimeData: JSON.stringify({ - message: 'This always evaluates to falsy. Consider refactoring this code.', - secondaryLocations: [ - { - message: 'Evaluated here to be falsy', - column: 13, - line: 3, - endColumn: 14, - endLine: 3, - }, - ], - }), + options: ['sonar-runtime'], + errors: [ + { + messageId: 'sonarRuntime', + data: { + value: 'falsy', + sonarRuntimeData: JSON.stringify({ + message: 'This always evaluates to falsy. Consider refactoring this code.', + secondaryLocations: [ + { + message: 'Evaluated here to be falsy', + column: 13, + line: 3, + endColumn: 14, + endLine: 3, + }, + ], + }), + }, + line: 4, + column: 16, + endLine: 4, + endColumn: 17, }, - line: 4, - column: 16, - endLine: 4, - endColumn: 17, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` function bar(x: boolean) { if (x) { x = 42; @@ -296,23 +297,23 @@ describe('S2589', () => { foo(!x) // Noncompliant } }`, - options: ['sonar-runtime'], - errors: [ - { - messageId: 'sonarRuntime', - data: { - value: 'falsy', - sonarRuntimeData: falsySonarRuntimeData, + options: ['sonar-runtime'], + errors: [ + { + messageId: 'sonarRuntime', + data: { + value: 'falsy', + sonarRuntimeData: falsySonarRuntimeData, + }, + line: 6, + column: 16, + endLine: 6, + endColumn: 17, }, - line: 6, - column: 16, - endLine: 6, - endColumn: 17, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` function bar(x: boolean) { if (x) { return foo() || x; // OK @@ -322,67 +323,67 @@ describe('S2589', () => { bar() || x || bar(); // FN, not supported } }`, - options: ['sonar-runtime'], - errors: [ - { - messageId: 'sonarRuntime', - data: { - value: 'falsy', - sonarRuntimeData: falsySonarRuntimeData, + options: ['sonar-runtime'], + errors: [ + { + messageId: 'sonarRuntime', + data: { + value: 'falsy', + sonarRuntimeData: falsySonarRuntimeData, + }, + line: 6, + column: 11, + endLine: 6, + endColumn: 12, }, - line: 6, - column: 11, - endLine: 6, - endColumn: 12, - }, - { - messageId: 'sonarRuntime', - data: { - value: 'falsy', - sonarRuntimeData: falsySonarRuntimeData, + { + messageId: 'sonarRuntime', + data: { + value: 'falsy', + sonarRuntimeData: falsySonarRuntimeData, + }, + line: 7, + column: 11, + endLine: 7, + endColumn: 12, }, - line: 7, - column: 11, - endLine: 7, - endColumn: 12, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` function bar(x: boolean) { if (!!x) { x && foo(); // Noncompliant } }`, - options: ['sonar-runtime'], - errors: [ - { - messageId: 'sonarRuntime', - data: { - value: 'truthy', - sonarRuntimeData: JSON.stringify({ - message: 'This always evaluates to truthy. Consider refactoring this code.', - secondaryLocations: [ - { - message: 'Evaluated here to be truthy', - column: 14, - line: 3, - endColumn: 15, - endLine: 3, - }, - ], - }), + options: ['sonar-runtime'], + errors: [ + { + messageId: 'sonarRuntime', + data: { + value: 'truthy', + sonarRuntimeData: JSON.stringify({ + message: 'This always evaluates to truthy. Consider refactoring this code.', + secondaryLocations: [ + { + message: 'Evaluated here to be truthy', + column: 14, + line: 3, + endColumn: 15, + endLine: 3, + }, + ], + }), + }, + line: 4, + column: 11, + endLine: 4, + endColumn: 12, }, - line: 4, - column: 11, - endLine: 4, - endColumn: 12, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` function render(children, right) { if (right) { return ( @@ -393,32 +394,33 @@ describe('S2589', () => { } } `, - options: ['sonar-runtime'], - errors: [ - { - messageId: 'sonarRuntime', - data: { - value: 'truthy', - sonarRuntimeData: JSON.stringify({ - message: 'This always evaluates to truthy. Consider refactoring this code.', - secondaryLocations: [ - { - message: 'Evaluated here to be truthy', - column: 12, - line: 3, - endColumn: 17, - endLine: 3, - }, - ], - }), + options: ['sonar-runtime'], + errors: [ + { + messageId: 'sonarRuntime', + data: { + value: 'truthy', + sonarRuntimeData: JSON.stringify({ + message: 'This always evaluates to truthy. Consider refactoring this code.', + secondaryLocations: [ + { + message: 'Evaluated here to be truthy', + column: 12, + line: 3, + endColumn: 17, + endLine: 3, + }, + ], + }), + }, + line: 6, + column: 16, + endLine: 6, + endColumn: 21, }, - line: 6, - column: 16, - endLine: 6, - endColumn: 21, - }, - ], - }, - ], + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2598/unit.test.ts b/packages/jsts/src/rules/S2598/unit.test.ts index 0cc08a1081..ed3a4e7f18 100644 --- a/packages/jsts/src/rules/S2598/unit.test.ts +++ b/packages/jsts/src/rules/S2598/unit.test.ts @@ -16,51 +16,52 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2598', () => { - const ruleTester = new RuleTester(); + it('S2598', () => { + const ruleTester = new RuleTester(); - function encodedMessage( - message: string, - secondary?: { line: number; column: number; endColumn: number; endLine: number }, - ) { - let secondaryLocations = []; - if (secondary) { - secondaryLocations = [ - { - message: 'no destination specified', - column: secondary.column, - line: secondary.line, - endColumn: secondary.endColumn, - endLine: secondary.endLine, - }, - ]; + function encodedMessage( + message: string, + secondary?: { line: number; column: number; endColumn: number; endLine: number }, + ) { + let secondaryLocations = []; + if (secondary) { + secondaryLocations = [ + { + message: 'no destination specified', + column: secondary.column, + line: secondary.line, + endColumn: secondary.endColumn, + endLine: secondary.endLine, + }, + ]; + } + return JSON.stringify({ + message, + secondaryLocations, + }); } - return JSON.stringify({ - message, - secondaryLocations, - }); - } - ruleTester.run('File uploads should be restricted', rule, { - valid: [ - { - code: ` + ruleTester.run('File uploads should be restricted', rule, { + valid: [ + { + code: ` const formidable = require('formidable'); const form = formidable(options); `, - }, - { - code: ` + }, + { + code: ` const multer = require('multer'); const upload = multer(); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const formidableModule = require('formidable'); const { formidable } = require('formidable'); const { formidable: formidableAlias } = require('formidable'); @@ -74,10 +75,10 @@ describe('S2598', () => { const form6 = new Formidable.Foo({ keepExtensions: true }); // OK `, - errors: 5, - }, - { - code: ` + errors: 5, + }, + { + code: ` import formidableModule from 'formidable'; import { formidable } from 'formidable'; import { IncomingForm } from 'formidable'; @@ -88,10 +89,10 @@ describe('S2598', () => { const form4 = new IncomingForm({ keepExtensions: true }); // Noncompliant const form5 = new Formidable({ keepExtensions: true }); // Noncompliant `, - errors: 4, - }, - { - code: ` + errors: 4, + }, + { + code: ` import { formidable } from 'formidable'; const form0 = formidable({ keepExtensions: false, uploadDir: './uploads/' }); // OK const form1 = formidable({ uploadDir: './uploads/' }); // OK @@ -102,21 +103,21 @@ describe('S2598', () => { const form6 = formidable({ keepExtensions: 42, uploadDir: './uploads/' }); // OK const form7 = formidable({ keepExtensions: 0, uploadDir: './uploads/' }); // OK `, - errors: [ - { message: encodedMessage('Restrict the extension of uploaded files.'), line: 5 }, - { - message: encodedMessage( - 'Restrict the extension and folder destination of uploaded files.', - ), - line: 6, - }, - { message: encodedMessage('Restrict folder destination of uploaded files.'), line: 7 }, - { message: encodedMessage('Restrict folder destination of uploaded files.'), line: 8 }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { message: encodedMessage('Restrict the extension of uploaded files.'), line: 5 }, + { + message: encodedMessage( + 'Restrict the extension and folder destination of uploaded files.', + ), + line: 6, + }, + { message: encodedMessage('Restrict folder destination of uploaded files.'), line: 7 }, + { message: encodedMessage('Restrict folder destination of uploaded files.'), line: 8 }, + ], + options: ['sonar-runtime'], + }, + { + code: ` import { formidable } from 'formidable'; const optionsOk = { keepExtensions: false, uploadDir: './uploads/' }; @@ -134,14 +135,14 @@ describe('S2598', () => { const optionsNotObject = 42; const form4 = formidable(optionsNotObject); // OK `, - errors: [ - { message: encodedMessage('Restrict the extension of uploaded files.'), line: 11 }, - { message: encodedMessage('Restrict the extension of uploaded files.'), line: 14 }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { message: encodedMessage('Restrict the extension of uploaded files.'), line: 11 }, + { message: encodedMessage('Restrict the extension of uploaded files.'), line: 14 }, + ], + options: ['sonar-runtime'], + }, + { + code: ` import { formidable } from 'formidable'; const form0 = formidable(); // Noncompliant @@ -165,20 +166,20 @@ describe('S2598', () => { foo(formidable()); // OK `, - errors: [ - { message: encodedMessage('Restrict folder destination of uploaded files.'), line: 3 }, - { message: encodedMessage('Restrict the extension of uploaded files.'), line: 5 }, - { - message: encodedMessage( - 'Restrict the extension and folder destination of uploaded files.', - ), - line: 17, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { message: encodedMessage('Restrict folder destination of uploaded files.'), line: 3 }, + { message: encodedMessage('Restrict the extension of uploaded files.'), line: 5 }, + { + message: encodedMessage( + 'Restrict the extension and folder destination of uploaded files.', + ), + line: 17, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` import { formidable } from 'formidable'; function foo() { @@ -191,19 +192,19 @@ describe('S2598', () => { form.uploadDir = './uploads/'; } `, - errors: [ - { - message: encodedMessage('Restrict folder destination of uploaded files.'), - line: 5, - column: 22, - endLine: 5, - endColumn: 32, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: encodedMessage('Restrict folder destination of uploaded files.'), + line: 5, + column: 22, + endLine: 5, + endColumn: 32, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const multer = require('multer'); multer({}); @@ -217,18 +218,18 @@ describe('S2598', () => { multer({ storage: myStorageNok }); // Noncompliant multer({ storage: unknownStorage }); `, - errors: [ - { - message: 'Restrict folder destination of uploaded files.', - line: 12, - endLine: 12, - column: 7, - endColumn: 13, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Restrict folder destination of uploaded files.', + line: 12, + endLine: 12, + column: 7, + endColumn: 13, + }, + ], + }, + { + code: ` import multer from 'multer'; const storage = multer.diskStorage({ filename: filenameFunc }); multer({ storage }); // Noncompliant @@ -240,46 +241,47 @@ describe('S2598', () => { multer({ storage: foo.bar(storageOptions) }); multer({ storage: multer.diskStorage() }); `, - errors: [ - { - message: encodedMessage('Restrict folder destination of uploaded files.', { - line: 3, - endLine: 3, - column: 22, - endColumn: 40, - }), - line: 4, - }, - { - message: encodedMessage('Restrict folder destination of uploaded files.', { + errors: [ + { + message: encodedMessage('Restrict folder destination of uploaded files.', { + line: 3, + endLine: 3, + column: 22, + endColumn: 40, + }), + line: 4, + }, + { + message: encodedMessage('Restrict folder destination of uploaded files.', { + line: 5, + endLine: 5, + column: 24, + endColumn: 42, + }), line: 5, - endLine: 5, - column: 24, - endColumn: 42, - }), - line: 5, - }, - { - message: encodedMessage('Restrict folder destination of uploaded files.', { - line: 3, - endLine: 3, - column: 22, - endColumn: 40, - }), - line: 7, - }, - { - message: encodedMessage('Restrict folder destination of uploaded files.', { + }, + { + message: encodedMessage('Restrict folder destination of uploaded files.', { + line: 3, + endLine: 3, + column: 22, + endColumn: 40, + }), + line: 7, + }, + { + message: encodedMessage('Restrict folder destination of uploaded files.', { + line: 9, + endLine: 9, + column: 24, + endColumn: 42, + }), line: 9, - endLine: 9, - column: 24, - endColumn: 42, - }), - line: 9, - }, - ], - options: ['sonar-runtime'], - }, - ], + }, + ], + options: ['sonar-runtime'], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2612/unit.test.ts b/packages/jsts/src/rules/S2612/unit.test.ts index ee926dd6c4..e1de6f1ed0 100644 --- a/packages/jsts/src/rules/S2612/unit.test.ts +++ b/packages/jsts/src/rules/S2612/unit.test.ts @@ -16,13 +16,14 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2612', () => { - let tests = { - valid: [ - { - code: ` + it('S2612', () => { + let tests = { + valid: [ + { + code: ` const fs = require('fs'); // Octal @@ -58,9 +59,9 @@ describe('S2612', () => { // Variable let doChmod = (mode) => fs.chmodSync("/tmp/fs", mode); // Compliant; mode value is unknown `, - }, - { - code: ` + }, + { + code: ` process = require('process'); // Octal @@ -84,9 +85,9 @@ describe('S2612', () => { // Variable let updateUmask = (mode) => process.umask(mode); // Compliant; mode value is unknown `, - }, - { - code: ` + }, + { + code: ` // fs.constants fs.chmodSync("/tmp/fs", fs.constants.S_IRUSR); // Compliant -r-------- fs.chmodSync("/tmp/fs", fs.constants.S_IWUSR); // Compliant --w------- @@ -107,40 +108,40 @@ describe('S2612', () => { fs.chmodSync("/tmp/fs", fs.bla); fs.chmodSync("/tmp/fs", /rwx/); `, - }, - { - code: ` + }, + { + code: ` const x = y; const y = x; fs.chmodSync("/tmp/fs", x); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const fs = require('fs'); // Octal fs.chmodSync("/tmp/fs", 0o0777); // Sensitive -rwxrwxrwx`, - errors: [ - { - message: 'Make sure this permission is safe.', - line: 4, - column: 31, - endLine: 4, - endColumn: 37, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Make sure this permission is safe.', + line: 4, + column: 31, + endLine: 4, + endColumn: 37, + }, + ], + }, + { + code: ` const fs = require('node:fs'); // Octal fs.chmodSync("/tmp/fs", 0o0777); // Sensitive -rwxrwxrwx`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const fs = require('fs'); fs.chmod("/tmp/fs", 0o0777); // Sensitive -rwxrwxrwx @@ -149,10 +150,10 @@ describe('S2612', () => { fs.fchmodSync("/tmp/fs", 0o0777); // Sensitive -rwxrwxrwx fs.lchmod("/tmp/fs", 0o0777); // Sensitive -rwxrwxrwx fs.lchmodSync("/tmp/fs", 0o0777); // Sensitive -rwxrwxrwx`, - errors: 6, - }, - { - code: ` + errors: 6, + }, + { + code: ` const fsPromises = require('fs').promises; fsPromises.chmod("/tmp/fs", 0o0777); // Sensitive -rwxrwxrwx @@ -161,10 +162,10 @@ describe('S2612', () => { fsPromises.fchmodSync("/tmp/fs", 0o0777); // Sensitive -rwxrwxrwx fsPromises.lchmod("/tmp/fs", 0o0777); // Sensitive -rwxrwxrwx fsPromises.lchmodSync("/tmp/fs", 0o0777); // Sensitive -rwxrwxrwx`, - errors: 6, - }, - { - code: ` + errors: 6, + }, + { + code: ` const fs = require('fs'); // Octal @@ -175,10 +176,10 @@ describe('S2612', () => { fs.chmodSync("/tmp/fs", 0o07); // Sensitive -------rwx fs.chmodSync("/tmp/fs", 0o7); // Sensitive -------rwx `, - errors: 6, - }, - { - code: ` + errors: 6, + }, + { + code: ` const fs = require('fs'); // String @@ -193,10 +194,10 @@ describe('S2612', () => { fs.chmodSync("/tmp/fs", "007"); // Sensitive -------rwx fs.chmodSync("/tmp/fs", "07"); // Sensitive -------rwx `, - errors: 10, - }, - { - code: ` + errors: 10, + }, + { + code: ` const fs = require('fs'); // Decimal @@ -204,10 +205,10 @@ describe('S2612', () => { fs.chmodSync("/tmp/fs", 4); // Sensitive; 4 % 8 = 4 -------r-- fs.chmodSync("/tmp/fs", 260); // Sensitive; 260 % 8 = 4 -r-----r-- `, - errors: 2, - }, - { - code: ` + errors: 2, + }, + { + code: ` // FileHandler async function fileHandler() { let filehandle; @@ -221,35 +222,35 @@ describe('S2612', () => { } } `, - errors: [ - { - message: 'Make sure this permission is safe.', - line: 8, - column: 30, - endLine: 8, - endColumn: 35, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Make sure this permission is safe.', + line: 8, + column: 30, + endLine: 8, + endColumn: 35, + }, + ], + }, + { + code: ` var process = require('process'); // Octal process.umask(0o000); // Sensitive `, - errors: [ - { - message: 'Make sure this permission is safe.', - line: 5, - column: 19, - endLine: 5, - endColumn: 24, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Make sure this permission is safe.', + line: 5, + column: 19, + endLine: 5, + endColumn: 24, + }, + ], + }, + { + code: ` var process = require('process'); // Octal @@ -270,10 +271,10 @@ describe('S2612', () => { process.umask(0); // Sensitive 0o000 process.umask(18); // Sensitive 0o022 `, - errors: 12, - }, - { - code: ` + errors: 12, + }, + { + code: ` // fs.constants fs.chmodSync("/tmp/fs", fs.constants.S_IROTH); // Sensitive -------r-- fs.chmodSync("/tmp/fs", fs.constants.S_IWOTH); // Sensitive --------w- @@ -282,22 +283,23 @@ describe('S2612', () => { fs.chmodSync("/tmp/fs", fs.constants.S_IRWXU | fs.constants.S_IRWXG | fs.constants.S_IRWXO); // Sensitive -rwxrwxrwx fs.chmodSync("/tmp/fs", fs.constants.S_IROTH | fs.constants.S_IRGRP | fs.constants.S_IRUSR); // Sensitive -r--r--r-- `, - errors: 6, - }, - { - code: ` + errors: 6, + }, + { + code: ` const mode = fs.constants.S_IROTH; fs.chmodSync("/tmp/fs", mode); // Sensitive -------r-- fs.chmodSync("/tmp/fs", fs.constants.S_IRWXU | mode); // Sensitive -------r-- `, - errors: 2, - }, - ], - }; + errors: 2, + }, + ], + }; - const ruleTester = new RuleTester(); - ruleTester.run('Using publicly writable directories is security-sensitive', rule, tests); + const ruleTester = new RuleTester(); + ruleTester.run('Using publicly writable directories is security-sensitive', rule, tests); - const ruleTesterTs = new RuleTester(); - ruleTesterTs.run('Using publicly writable directories is security-sensitive [TS]', rule, tests); + const ruleTesterTs = new RuleTester(); + ruleTesterTs.run('Using publicly writable directories is security-sensitive [TS]', rule, tests); + }); }); diff --git a/packages/jsts/src/rules/S2681/unit.test.ts b/packages/jsts/src/rules/S2681/unit.test.ts index 887011ef4a..4d12d0da41 100644 --- a/packages/jsts/src/rules/S2681/unit.test.ts +++ b/packages/jsts/src/rules/S2681/unit.test.ts @@ -16,150 +16,151 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2681', () => { - const ruleTester = new RuleTester(); - const ruleTesterTs = new RuleTester(); + it('S2681', () => { + const ruleTester = new RuleTester(); + const ruleTesterTs = new RuleTester(); - ruleTester.run('Multiline blocks should be enclosed in curly braces', rule, { - valid: [ - { - code: ` + ruleTester.run('Multiline blocks should be enclosed in curly braces', rule, { + valid: [ + { + code: ` if (condition) { action1(); action2(); } `, - }, - { - code: ` + }, + { + code: ` if (condition) action1(); action2(); `, - }, - { - code: ` + }, + { + code: ` if (condition) action1(); action2(); `, - }, - { - code: ` + }, + { + code: ` if (condition) action1(); action2(); `, - }, - { - code: ` + }, + { + code: ` for(var i = 1; i < 3; i++) { action1(); action2(); } `, - }, - { - code: ` + }, + { + code: ` while (condition) { action1(); action2(); } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` if (condition) action1(); action2(); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` if (condition) action1(); action2(); action3(); `, - errors: [ - { - message: `This line will not be executed conditionally; only the first line of this 3-line block will be. The rest will execute unconditionally.`, - line: 4, - endLine: 4, - column: 9, - endColumn: 19, - }, - ], - }, - { - code: ` + errors: [ + { + message: `This line will not be executed conditionally; only the first line of this 3-line block will be. The rest will execute unconditionally.`, + line: 4, + endLine: 4, + column: 9, + endColumn: 19, + }, + ], + }, + { + code: ` if (condition) action1(); action2(); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` if (condition) action1(); action2(); action3(); `, - errors: 1, - }, - { - code: `if (condition) action1(); action2();`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: `if (condition) action1(); action2();`, + errors: 1, + }, + { + code: ` if (condition) action1(); action2(); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` for(var i = 1; i < 3; i++) action1(); action2(); `, - errors: [ - { - message: `This line will not be executed in a loop; only the first line of this 2-line block will be. The rest will execute only once.`, - line: 4, - endLine: 4, - column: 9, - endColumn: 19, - }, - ], - }, - { - code: ` + errors: [ + { + message: `This line will not be executed in a loop; only the first line of this 2-line block will be. The rest will execute only once.`, + line: 4, + endLine: 4, + column: 9, + endColumn: 19, + }, + ], + }, + { + code: ` for(var x in obj) action1(); action2(); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` for(var x of obj) action1(); action2(); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` function foo() { if (condition) { action1(); @@ -171,23 +172,23 @@ describe('S2681', () => { action2(); } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` while (condition) action1(); action2(); `, - errors: 1, - }, - ], - }); + errors: 1, + }, + ], + }); - ruleTesterTs.run('TS: Multiline blocks should be enclosed in curly braces', rule, { - valid: [ - { - code: ` + ruleTesterTs.run('TS: Multiline blocks should be enclosed in curly braces', rule, { + valid: [ + { + code: ` namespace A { if (condition) { action1(); @@ -195,29 +196,30 @@ describe('S2681', () => { } } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` namespace A { if (condition) action1(); action2(); } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` module B { if (condition) action1(); action2(); } `, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2692/unit.test.ts b/packages/jsts/src/rules/S2692/unit.test.ts index c91ba95cfc..ee72773242 100644 --- a/packages/jsts/src/rules/S2692/unit.test.ts +++ b/packages/jsts/src/rules/S2692/unit.test.ts @@ -16,50 +16,52 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2692', () => { - const ruleTester = new RuleTester(); - ruleTester.run(`"indexOf" checks should not be for positive numbers`, rule, { - valid: [ - { - code: `a.indexOf("str", 1) > 0;`, - }, - { - code: `a.indexOf("str") > -1;`, - }, - { - code: `"str".indexOf("str") > 0;`, - }, - { - code: `[].indexOf(a) >= 0;`, - }, - { - code: `(new Array()).indexOf(a) >= 0;`, - }, - ], - invalid: [ - { - code: `[].indexOf("str") > 0;`, - errors: [ - { - message: - "This check ignores index 0; consider using 'includes' method to make this check safe and explicit.", - line: 1, - endLine: 1, - column: 1, - endColumn: 22, - }, - ], - }, - { - code: `[].indexOf(a) > 0;`, - errors: 1, - }, - { - code: `(new Array()).indexOf(a) > 0;`, - errors: 1, - }, - ], + it('S2692', () => { + const ruleTester = new RuleTester(); + ruleTester.run(`"indexOf" checks should not be for positive numbers`, rule, { + valid: [ + { + code: `a.indexOf("str", 1) > 0;`, + }, + { + code: `a.indexOf("str") > -1;`, + }, + { + code: `"str".indexOf("str") > 0;`, + }, + { + code: `[].indexOf(a) >= 0;`, + }, + { + code: `(new Array()).indexOf(a) >= 0;`, + }, + ], + invalid: [ + { + code: `[].indexOf("str") > 0;`, + errors: [ + { + message: + "This check ignores index 0; consider using 'includes' method to make this check safe and explicit.", + line: 1, + endLine: 1, + column: 1, + endColumn: 22, + }, + ], + }, + { + code: `[].indexOf(a) > 0;`, + errors: 1, + }, + { + code: `(new Array()).indexOf(a) > 0;`, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2703/unit.test.ts b/packages/jsts/src/rules/S2703/unit.test.ts index a4b38009f6..1c62980e40 100644 --- a/packages/jsts/src/rules/S2703/unit.test.ts +++ b/packages/jsts/src/rules/S2703/unit.test.ts @@ -16,110 +16,112 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2703', () => { - const ruleTester = new RuleTester(); - ruleTester.run('No implicit global', rule, { - valid: [ - { - code: ` + it('S2703', () => { + const ruleTester = new RuleTester(); + ruleTester.run('No implicit global', rule, { + valid: [ + { + code: ` function fun() { var y = 3; // OK }`, - }, - { - code: ` + }, + { + code: ` function fun() { otherFun(); // OK }`, - }, - { - code: ` + }, + { + code: ` function fun() { amplify.subscribe() }`, - }, - { - code: `$()`, - }, - { - code: ` + }, + { + code: `$()`, + }, + { + code: ` let unflowed; unflowed = false;`, - }, - { - code: ` + }, + { + code: ` var foo = exports = module.exports = {} // OK `, - }, - { - code: `module = 1; // OK`, - }, - { - code: `jQuery = $ = $$`, - }, - ], - invalid: [ - { - code: ` + }, + { + code: `module = 1; // OK`, + }, + { + code: `jQuery = $ = $$`, + }, + ], + invalid: [ + { + code: ` function fun() { x = 1; //^ } `, - errors: [ - { - message: `Add the "let", "const" or "var" keyword to this declaration of "x" to make it explicit.`, - line: 3, - endLine: 3, - column: 9, - endColumn: 10, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Add the "let", "const" or "var" keyword to this declaration of "x" to make it explicit.`, + line: 3, + endLine: 3, + column: 9, + endColumn: 10, + }, + ], + }, + { + code: ` for (z in obj) {} `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` function fun() { x = 1; //^ x = 2; } `, - errors: 1, - }, - { - code: `for (j = 0; j < array.length; j++){}`, - errors: 1, - }, - { - code: `for (k of obj){}`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: `for (j = 0; j < array.length; j++){}`, + errors: 1, + }, + { + code: `for (k of obj){}`, + errors: 1, + }, + { + code: ` function fun(){ z = 1; // OK var z; var var1 = var2 = 1; // Noncompliant fun(arguments) // OK }`, - errors: [ - { - message: `Add the "let", "const" or "var" keyword to this declaration of "var2" to make it explicit.`, - line: 5, - endLine: 5, - column: 20, - endColumn: 24, - }, - ], - }, - ], + errors: [ + { + message: `Add the "let", "const" or "var" keyword to this declaration of "var2" to make it explicit.`, + line: 5, + endLine: 5, + column: 20, + endColumn: 24, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2737/unit.test.ts b/packages/jsts/src/rules/S2737/unit.test.ts index 7afc9940d2..025d732d10 100644 --- a/packages/jsts/src/rules/S2737/unit.test.ts +++ b/packages/jsts/src/rules/S2737/unit.test.ts @@ -16,86 +16,88 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2737', () => { - const ruleTester = new RuleTester(); + it('S2737', () => { + const ruleTester = new RuleTester(); - ruleTester.run('no-useless-catch', rule, { - valid: [ - { code: `try {} catch (e) {}` }, - { code: `try {} catch { throw "Error"; }` }, - { - code: `try {} catch (e) { + ruleTester.run('no-useless-catch', rule, { + valid: [ + { code: `try {} catch (e) {}` }, + { code: `try {} catch { throw "Error"; }` }, + { + code: `try {} catch (e) { foo(); throw e; }`, - }, - { - code: `try {} catch({ message }) { + }, + { + code: `try {} catch({ message }) { throw { message }; // OK, not useless, we might ignore other properties of exception }`, - }, - { - code: `try {} catch (e) { + }, + { + code: `try {} catch (e) { if (x) { throw e; } }`, - }, - { - code: `try {} catch(e) { throw "foo"; }`, - }, - { - code: `try {} catch(e) { throw new Error("improve error message"); }`, - }, - ], - invalid: [ - { - code: `try {} catch (e) { throw e; }`, - errors: [ - { - messageId: 'uselessCatch', - line: 1, - endLine: 1, - column: 8, - endColumn: 13, - }, - ], - }, - { - code: `try {} catch(e) { + }, + { + code: `try {} catch(e) { throw "foo"; }`, + }, + { + code: `try {} catch(e) { throw new Error("improve error message"); }`, + }, + ], + invalid: [ + { + code: `try {} catch (e) { throw e; }`, + errors: [ + { + messageId: 'uselessCatch', + line: 1, + endLine: 1, + column: 8, + endColumn: 13, + }, + ], + }, + { + code: `try {} catch(e) { // some comment throw e; }`, - errors: [ - { - messageId: 'uselessCatch', - line: 1, - endLine: 1, - column: 8, - endColumn: 13, - }, - ], - }, - { - code: `try { + errors: [ + { + messageId: 'uselessCatch', + line: 1, + endLine: 1, + column: 8, + endColumn: 13, + }, + ], + }, + { + code: `try { doSomething(); } catch(e) { throw e; } finally { // ... }`, - errors: [ - { - messageId: 'uselessCatch', - line: 3, - endLine: 3, - column: 9, - endColumn: 14, - }, - ], - }, - ], + errors: [ + { + messageId: 'uselessCatch', + line: 3, + endLine: 3, + column: 9, + endColumn: 14, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2755/unit.test.ts b/packages/jsts/src/rules/S2755/unit.test.ts index 48f69262bc..db21a09a2f 100644 --- a/packages/jsts/src/rules/S2755/unit.test.ts +++ b/packages/jsts/src/rules/S2755/unit.test.ts @@ -16,88 +16,90 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2755', () => { - const tests = { - valid: [ - { - code: ` + it('S2755', () => { + const tests = { + valid: [ + { + code: ` const libxmljs = require("libxmljs"); var xmlDoc = libxmljs.parseXml(xml, { noblanks: true, nocdata: true });`, - }, - { - code: ` + }, + { + code: ` const libxmljs = require("libxmljs"); var xmlDoc = libxmljs.parseXmlString(xml, { noblanks: true, nocdata: true });`, - }, - { - code: ` + }, + { + code: ` const libxmljs = require("libxmljs"); var xmlDoc = libxmljs.parseXmlString(xml, { noblanks: true, noent: false, nocdata: true });`, - }, - { - code: ` + }, + { + code: ` import libxmljs from "libxmljs"; var xmlDoc = libxmljs.parseXmlString(xml, { noblanks: true, nocdata: true });`, - }, - { - code: ` + }, + { + code: ` import { parseXmlString } from "libxmljs"; var xmlDoc = parseXmlString(xml, { noblanks: true, noent: false, nocdata: true });`, - }, - { - code: ` + }, + { + code: ` var xmlDoc = parseXmlString(xml, { noblanks: true, noent: true, nocdata: true });`, - }, - { - code: ` + }, + { + code: ` const libxmljs = require("libxmljs"); var xmlDoc = libxmljs.parseXmlString({ noblanks: true, noent: true, nocdata: true });`, - errors: 1, - }, - ], - invalid: [ - { - code: ` + errors: 1, + }, + ], + invalid: [ + { + code: ` const libxmljs = require("libxmljs"); var xmlDoc = libxmljs.parseXml(xml, { noblanks: true, noent: true, nocdata: true });`, - errors: [ - { - message: - '{"message":"Disable access to external entities in XML parsing.","secondaryLocations":[{"column":21,"line":3,"endColumn":38,"endLine":3}]}', - line: 3, - endLine: 3, - column: 63, - endColumn: 74, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: + '{"message":"Disable access to external entities in XML parsing.","secondaryLocations":[{"column":21,"line":3,"endColumn":38,"endLine":3}]}', + line: 3, + endLine: 3, + column: 63, + endColumn: 74, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const libxmljs = require("libxmljs"); var xmlDoc = libxmljs.parseXmlString(xml, { noblanks: true, noent: true, nocdata: true });`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` import libxmljs from "libxmljs"; var xmlDoc = libxmljs.parseXmlString(xml, { noblanks: true, noent: true, nocdata: true });`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` import { parseXmlString } from "libxmljs"; var xmlDoc = parseXmlString(xml, { noblanks: true, noent: true, nocdata: true });`, - errors: 1, - }, - ], - }; + errors: 1, + }, + ], + }; - const ruleTesterJs = new RuleTester(); - const ruleTesterTs = new RuleTester(); + const ruleTesterJs = new RuleTester(); + const ruleTesterTs = new RuleTester(); - ruleTesterJs.run('XML parsers should not be vulnerable to XXE attacks [js]', rule, tests); - ruleTesterTs.run('XML parsers should not be vulnerable to XXE attacks [ts]', rule, tests); + ruleTesterJs.run('XML parsers should not be vulnerable to XXE attacks [js]', rule, tests); + ruleTesterTs.run('XML parsers should not be vulnerable to XXE attacks [ts]', rule, tests); + }); }); diff --git a/packages/jsts/src/rules/S2757/unit.test.ts b/packages/jsts/src/rules/S2757/unit.test.ts index 659c7184e3..936d324815 100644 --- a/packages/jsts/src/rules/S2757/unit.test.ts +++ b/packages/jsts/src/rules/S2757/unit.test.ts @@ -16,15 +16,16 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2757', () => { - const ruleTester = new RuleTester(); + it('S2757', () => { + const ruleTester = new RuleTester(); - ruleTester.run("Non-existent operators '=+', '=-' and '=!' should not be used", rule, { - valid: [ - { - code: ` + ruleTester.run("Non-existent operators '=+', '=-' and '=!' should not be used", rule, { + valid: [ + { + code: ` x = y; x += y; x = + y; @@ -39,106 +40,107 @@ describe('S2757', () => { const z = + 1; other =~ 1; `, - }, - ], - invalid: [ - { - code: `x =+ y;`, - errors: [ - { - messageId: `useExistingOperator`, - data: { - operator: '+', - }, - line: 1, - endLine: 1, - column: 3, - endColumn: 5, - suggestions: [ - { - messageId: 'suggestExistingOperator', - data: { - operator: '+=', + }, + ], + invalid: [ + { + code: `x =+ y;`, + errors: [ + { + messageId: `useExistingOperator`, + data: { + operator: '+', + }, + line: 1, + endLine: 1, + column: 3, + endColumn: 5, + suggestions: [ + { + messageId: 'suggestExistingOperator', + data: { + operator: '+=', + }, + output: `x += y;`, }, - output: `x += y;`, + ], + }, + ], + }, + { + code: `x =- y;`, + errors: [ + { + messageId: `useExistingOperator`, + data: { + operator: '-', }, - ], - }, - ], - }, - { - code: `x =- y;`, - errors: [ - { - messageId: `useExistingOperator`, - data: { - operator: '-', + line: 1, + endLine: 1, + column: 3, + endColumn: 5, + suggestions: [ + { + output: 'x -= y;', + desc: 'Replace with "-=" operator', + }, + ], }, - line: 1, - endLine: 1, - column: 3, - endColumn: 5, - suggestions: [ - { - output: 'x -= y;', - desc: 'Replace with "-=" operator', + ], + }, + { + code: `x =! y;`, + errors: [ + { + messageId: `useExistingOperator`, + data: { + operator: '!', }, - ], - }, - ], - }, - { - code: `x =! y;`, - errors: [ - { - messageId: `useExistingOperator`, - data: { - operator: '!', + line: 1, + endLine: 1, + column: 3, + endColumn: 5, + suggestions: [ + { + output: 'x != y;', + desc: 'Replace with "!=" operator', + }, + ], }, - line: 1, - endLine: 1, - column: 3, - endColumn: 5, - suggestions: [ - { - output: 'x != y;', - desc: 'Replace with "!=" operator', + ], + }, + { + code: `const x =! y;`, + errors: [ + { + messageId: `useExistingOperator`, + data: { + operator: '!', }, - ], - }, - ], - }, - { - code: `const x =! y;`, - errors: [ - { - messageId: `useExistingOperator`, - data: { - operator: '!', + line: 1, + endLine: 1, + column: 9, + endColumn: 11, }, - line: 1, - endLine: 1, - column: 9, - endColumn: 11, - }, - ], - }, - { - code: `let x =! y;`, - errors: [ - { - messageId: `useExistingOperator`, - data: { - operator: '!', + ], + }, + { + code: `let x =! y;`, + errors: [ + { + messageId: `useExistingOperator`, + data: { + operator: '!', + }, + line: 1, + endLine: 1, + column: 7, + endColumn: 9, + suggestions: [], }, - line: 1, - endLine: 1, - column: 7, - endColumn: 9, - suggestions: [], - }, - ], - }, - ], + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2814/unit.test.ts b/packages/jsts/src/rules/S2814/unit.test.ts index 4f1caa6b56..ef79c3e4de 100644 --- a/packages/jsts/src/rules/S2814/unit.test.ts +++ b/packages/jsts/src/rules/S2814/unit.test.ts @@ -16,36 +16,38 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2814', () => { - const ruleTester = new RuleTester(); + it('S2814', () => { + const ruleTester = new RuleTester(); - ruleTester.run(`Variables and functions should not be redeclared`, rule, { - valid: [ - { - code: ` + ruleTester.run(`Variables and functions should not be redeclared`, rule, { + valid: [ + { + code: ` export const FOO = 'FOO'; export type FOO = typeof FOO;`, - }, - { - code: ` + }, + { + code: ` import FOO from "foo"; export type FOO = 'F' | 'O' | 'O'; `, - }, - ], - invalid: [ - { - code: `var a = 42; var a = 0;`, - errors: 1, - }, - { - code: ` + }, + ], + invalid: [ + { + code: `var a = 42; var a = 0;`, + errors: 1, + }, + { + code: ` export var FOO = 'FOO'; export var FOO = typeof FOO;`, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2817/unit.test.ts b/packages/jsts/src/rules/S2817/unit.test.ts index d5f74cd4e3..9b103aeb30 100644 --- a/packages/jsts/src/rules/S2817/unit.test.ts +++ b/packages/jsts/src/rules/S2817/unit.test.ts @@ -16,84 +16,86 @@ */ import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2817', () => { - const ruleTesterJs = new DefaultParserRuleTester(); - const ruleTesterTs = new RuleTester(); + it('S2817', () => { + const ruleTesterJs = new DefaultParserRuleTester(); + const ruleTesterTs = new RuleTester(); - ruleTesterJs.run('No issues without types', rule, { - valid: [ - { - code: ` + ruleTesterJs.run('No issues without types', rule, { + valid: [ + { + code: ` var db2 = openDatabase("myDb", "1.0", "P", 2*1024*1024); `, - }, - { - code: ` + }, + { + code: ` var db3 = this.openDatabase("myDb", "1.0", "P", 2*1024*1024, callback); `, - }, - { - code: ` + }, + { + code: ` var win = window; win.openDatabase("db","1.0","stuff",2*1024*1024); `, - }, - ], - invalid: [], - }); + }, + ], + invalid: [], + }); - ruleTesterTs.run('Web SQL databases should not be used', rule, { - valid: [ - { - code: ` + ruleTesterTs.run('Web SQL databases should not be used', rule, { + valid: [ + { + code: ` var deb = getDb(); var db4 = db.openDatabase("myDb", "1.0", "P", 2*1024*1024); `, - }, - { - code: ` + }, + { + code: ` function openDatabase() { } openDatabase(); `, - }, - { - code: ` + }, + { + code: ` var win = window; win.somethingElse(); // OK `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` var win = window; win.openDatabase("db","1.0","stuff",2*1024*1024); `, - errors: [ - { - line: 3, - column: 7, - endLine: 3, - endColumn: 23, - message: 'Convert this use of a Web SQL database to another technology.', - }, - ], - }, - { - code: ` + errors: [ + { + line: 3, + column: 7, + endLine: 3, + endColumn: 23, + message: 'Convert this use of a Web SQL database to another technology.', + }, + ], + }, + { + code: ` var db2 = openDatabase("myDb", "1.0", "P", 2*1024*1024); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` var db3 = this.openDatabase("myDb", "1.0", "P", 2*1024*1024, callback); `, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2819/unit.test.ts b/packages/jsts/src/rules/S2819/unit.test.ts index ac32550e8a..34f21fc661 100644 --- a/packages/jsts/src/rules/S2819/unit.test.ts +++ b/packages/jsts/src/rules/S2819/unit.test.ts @@ -16,104 +16,105 @@ */ import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2819', () => { - const ruleTesterJs = new DefaultParserRuleTester(); - const ruleTesterTs = new RuleTester(); + it('S2819', () => { + const ruleTesterJs = new DefaultParserRuleTester(); + const ruleTesterTs = new RuleTester(); - ruleTesterJs.run('No issues without types', rule, { - valid: [ - { - code: ` + ruleTesterJs.run('No issues without types', rule, { + valid: [ + { + code: ` var someWindow1 = window.open("url", "name"); someWindow1.postMessage("message", "*"); `, - }, - ], - invalid: [], - }); + }, + ], + invalid: [], + }); - ruleTesterTs.run('Origins should be verified during cross-origin communications', rule, { - valid: [ - { - code: ` + ruleTesterTs.run('Origins should be verified during cross-origin communications', rule, { + valid: [ + { + code: ` var someWindow1 = window.open("url", "name"); someWindow1.postMessage("message", "receiver"); `, - }, - { - code: ` + }, + { + code: ` postMessage("message", "receiver"); `, - }, - { - code: ` + }, + { + code: ` postMessage("message"); postMessage("message", "*", "something", "something else"); `, - }, - { - code: ` + }, + { + code: ` window.addEventListener("message", function(event) { if (event.origin !== "http://example.org") return; console.log(event.data); }); `, - }, - { - code: ` + }, + { + code: ` window.addEventListener("missing listener"); window.addEventListener("message", "not a function"); not_a_win_dow.addEventListener("message", () => {}); window.addEventListener("message", () => {}); // missing event parameter window.addEventListener("message", (...not_an_identifier) => {}); `, - }, - { - code: ` + }, + { + code: ` window.addEventListener("click", function(event) { // OK: event type is not "message" if (event.data !== "http://example.org") return; console.log(event.data); }); `, - }, - { - code: ` + }, + { + code: ` const processEvent = event => { if (event.origin !== "http://example.org") return } window.addEventListener('message', processEvent); `, - }, - { - code: ` + }, + { + code: ` const processEvent = event => { if (event.origin !== "http://example.org") return } window.addEventListener('message', event => processEvent(event)); `, - }, - { - code: ` + }, + { + code: ` window.addEventListener("message", function(event) { if (event.originalEvent.origin !== "http://example.org") return; }); `, - }, - { - code: ` + }, + { + code: ` window.addEventListener("message", function(event) { if (event.originalEvent.origin === "http://example.org" || event.origin === "http://example.org") return; }); `, - }, - { - code: ` + }, + { + code: ` window.addEventListener("message", function(event) { const _event = event.originalEvent || event; if (_event.origin !== "http://example.org") @@ -125,9 +126,9 @@ describe('S2819', () => { return; }); `, - }, - { - code: ` + }, + { + code: ` window.addEventListener("message", function(event) { var origin = event.originalEvent.origin || event.origin if (origin !== "http://example.org") @@ -139,77 +140,77 @@ describe('S2819', () => { return; }); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` var someWindow1 = window.open("url", "name"); someWindow1.postMessage("message", "*"); `, - errors: [{ messageId: 'specifyTarget' }], - }, - { - code: ` + errors: [{ messageId: 'specifyTarget' }], + }, + { + code: ` postMessage("message", "*"); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` this.postMessage("message", "*"); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` var someWindow2 = document.getElementById("frameId").contentWindow; someWindow2.postMessage("message", "*"); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` var someWindow3 = window.frames[1]; someWindow3.postMessage("message", "*"); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` getWindow().postMessage("message", "*"); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` window.addEventListener("message", function(event) { console.log(event.data); }); `, - errors: [{ messageId: 'verifyOrigin' }], - }, - { - code: ` + errors: [{ messageId: 'verifyOrigin' }], + }, + { + code: ` function eventHandler(event) { console.log(event.data); } window.addEventListener("message", eventHandler); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` window.addEventListener("message", function(event) { if (event.data !== "http://example.org") return; console.log(event.data); }); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const eventType = "message"; window.addEventListener(eventType, function(event) { if (event.data !== "http://example.org") @@ -217,24 +218,25 @@ describe('S2819', () => { console.log(event.data); }); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` window.addEventListener("message", function(event) { var origin = event.originalEvent.origin || event.origin; // coverage: must be tested }); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` window.addEventListener("message", function(event) { event.originalEvent.origin || event.origin; // coverage: we don't assign this anywhere }); `, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S2871/unit.test.ts b/packages/jsts/src/rules/S2871/unit.test.ts index f87810da48..fee7db74ad 100644 --- a/packages/jsts/src/rules/S2871/unit.test.ts +++ b/packages/jsts/src/rules/S2871/unit.test.ts @@ -16,67 +16,68 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2871', () => { - const ruleTester = new RuleTester(); - ruleTester.run( - `A compare function should be provided when using "Array.prototype.sort()"`, - rule, - { - valid: [ - { - code: ` + it('S2871', () => { + const ruleTester = new RuleTester(); + ruleTester.run( + `A compare function should be provided when using "Array.prototype.sort()"`, + rule, + { + valid: [ + { + code: ` var arrayOfNumbers = [80, 3, 9, 34, 23, 5, 1]; arrayOfNumbers.sort((n, m) => n - m); `, - }, - { - code: `unknownArrayType.sort();`, - }, - { - code: ` + }, + { + code: `unknownArrayType.sort();`, + }, + { + code: ` var arrayOfNumbers = [80, 3, 9, 34, 23, 5, 1]; arrayOfNumbers.custom_sort(); `, - }, - { - code: ` + }, + { + code: ` function f(a: any[]) { a.sort(undefined); } `, - }, - { - code: ` + }, + { + code: ` function f(a: any[]) { a.sort((a, b) => a - b); } `, - }, - { - code: ` + }, + { + code: ` function f(a: Array) { a.sort(undefined); } `, - }, - { - code: ` + }, + { + code: ` function f(a: Array) { a.sort((a, b) => a - b); } `, - }, - { - code: ` + }, + { + code: ` function f(a: { sort(): void }) { a.sort(); } `, - }, - { - code: ` + }, + { + code: ` class A { sort(): void {} } @@ -84,9 +85,9 @@ describe('S2871', () => { a.sort(); } `, - }, - { - code: ` + }, + { + code: ` interface A { sort(): void; } @@ -94,9 +95,9 @@ describe('S2871', () => { a.sort(); } `, - }, - { - code: ` + }, + { + code: ` interface A { sort(): void; } @@ -104,16 +105,16 @@ describe('S2871', () => { a.sort(); } `, - }, - { - code: ` + }, + { + code: ` function f(a: any) { a.sort(); } `, - }, - { - code: ` + }, + { + code: ` namespace UserDefined { interface Array { sort(): void; @@ -123,17 +124,17 @@ describe('S2871', () => { } } `, - }, - // optional chain - { - code: ` + }, + // optional chain + { + code: ` function f(a: any[]) { a?.sort((a, b) => a - b); } `, - }, - { - code: ` + }, + { + code: ` namespace UserDefined { interface Array { sort(): void; @@ -143,110 +144,110 @@ describe('S2871', () => { } } `, - }, - { - code: `Array.prototype.sort.apply([1, 2, 10])`, - }, - ], - invalid: [ - { - code: ` + }, + { + code: `Array.prototype.sort.apply([1, 2, 10])`, + }, + ], + invalid: [ + { + code: ` var arrayOfNumbers = [80, 3, 9, 34, 23, 5, 1]; arrayOfNumbers.sort(); `, - errors: [ - { - message: `Provide a compare function to avoid sorting elements alphabetically.`, - line: 3, - column: 22, - endLine: 3, - endColumn: 26, - suggestions: [ - { - messageId: 'suggestNumericOrder', - output: ` + errors: [ + { + message: `Provide a compare function to avoid sorting elements alphabetically.`, + line: 3, + column: 22, + endLine: 3, + endColumn: 26, + suggestions: [ + { + messageId: 'suggestNumericOrder', + output: ` var arrayOfNumbers = [80, 3, 9, 34, 23, 5, 1]; arrayOfNumbers.sort((a, b) => (a - b)); `, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` var emptyArrayOfNumbers: number[] = []; emptyArrayOfNumbers.sort(); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` function getArrayOfNumbers(): number[] {} getArrayOfNumbers().sort(); `, - errors: 1, - }, - { - code: `[80, 3, 9, 34, 23, 5, 1].sort();`, - errors: [ - { - messageId: 'provideCompareFunction', - suggestions: [ - { - desc: 'Add a comparator function to sort in ascending order', - output: '[80, 3, 9, 34, 23, 5, 1].sort((a, b) => (a - b));', - }, - ], - }, - ], - }, - { - code: '[Number("1"), Number("2"), Number("10")].sort();', - errors: [ - { - messageId: 'provideCompareFunction', - suggestions: [ - { - desc: 'Add a comparator function to sort in ascending order', - output: '[Number("1"), Number("2"), Number("10")].sort((a, b) => (a - b));', - }, - ], - }, - ], - }, - { - code: '[Number("1"), 2, Number("10")].sort();', - errors: [ - { - messageId: 'provideCompareFunction', - suggestions: [ - { - desc: 'Add a comparator function to sort in ascending order', - output: '[Number("1"), 2, Number("10")].sort((a, b) => (a - b));', - }, - ], - }, - ], - }, - { - code: '["1", 2, "10"].sort();', - errors: [ - { - messageId: 'provideCompareFunction', - suggestions: [], - }, - ], - }, - { - code: `[80n, 3n, 9n, 34n, 23n, 5n, 1n].sort();`, - errors: [ - { - messageId: 'provideCompareFunction', - suggestions: [ - { - desc: 'Add a comparator function to sort in ascending order', - output: `[80n, 3n, 9n, 34n, 23n, 5n, 1n].sort((a, b) => { + errors: 1, + }, + { + code: `[80, 3, 9, 34, 23, 5, 1].sort();`, + errors: [ + { + messageId: 'provideCompareFunction', + suggestions: [ + { + desc: 'Add a comparator function to sort in ascending order', + output: '[80, 3, 9, 34, 23, 5, 1].sort((a, b) => (a - b));', + }, + ], + }, + ], + }, + { + code: '[Number("1"), Number("2"), Number("10")].sort();', + errors: [ + { + messageId: 'provideCompareFunction', + suggestions: [ + { + desc: 'Add a comparator function to sort in ascending order', + output: '[Number("1"), Number("2"), Number("10")].sort((a, b) => (a - b));', + }, + ], + }, + ], + }, + { + code: '[Number("1"), 2, Number("10")].sort();', + errors: [ + { + messageId: 'provideCompareFunction', + suggestions: [ + { + desc: 'Add a comparator function to sort in ascending order', + output: '[Number("1"), 2, Number("10")].sort((a, b) => (a - b));', + }, + ], + }, + ], + }, + { + code: '["1", 2, "10"].sort();', + errors: [ + { + messageId: 'provideCompareFunction', + suggestions: [], + }, + ], + }, + { + code: `[80n, 3n, 9n, 34n, 23n, 5n, 1n].sort();`, + errors: [ + { + messageId: 'provideCompareFunction', + suggestions: [ + { + desc: 'Add a comparator function to sort in ascending order', + output: `[80n, 3n, 9n, 34n, 23n, 5n, 1n].sort((a, b) => { if (a < b) { return -1; } else if (a > b) { @@ -255,190 +256,191 @@ describe('S2871', () => { return 0; } });`, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` var arrayOfObjects = [{a: 2}, {a: 4}]; arrayOfObjects.sort(); `, - errors: [ - { - messageId: 'provideCompareFunction', - suggestions: [], - }, - ], - }, - { - code: ` + errors: [ + { + messageId: 'provideCompareFunction', + suggestions: [], + }, + ], + }, + { + code: ` interface MyCustomNumber extends Number {} const arrayOfCustomNumbers: MyCustomNumber[]; arrayOfCustomNumbers.sort(); `, - errors: [ - { - messageId: 'provideCompareFunction', - suggestions: [], - }, - ], - }, - { - code: ` + errors: [ + { + messageId: 'provideCompareFunction', + suggestions: [], + }, + ], + }, + { + code: ` function f(a: Array) { a.sort(); } `, - errors: [ - { - messageId: 'provideCompareFunction', - suggestions: [], - }, - ], - }, - { - code: ` + errors: [ + { + messageId: 'provideCompareFunction', + suggestions: [], + }, + ], + }, + { + code: ` function f(a: number[] | string[]) { a.sort(); } `, - errors: [ - { - messageId: 'provideCompareFunction', - suggestions: [], - }, - ], - }, - { - code: ` + errors: [ + { + messageId: 'provideCompareFunction', + suggestions: [], + }, + ], + }, + { + code: ` function f(a: T) { a.sort(); } `, - errors: [ - { - messageId: 'provideCompareFunction', - suggestions: [], - }, - ], - }, - { - code: ` + errors: [ + { + messageId: 'provideCompareFunction', + suggestions: [], + }, + ], + }, + { + code: ` function f(a: U) { a.sort(); } `, - errors: [ - { - messageId: 'provideCompareFunction', - suggestions: [], - }, - ], - }, - { - code: 'const array = ["foo", "bar"]; array.sort();', - errors: [ - { - messageId: 'provideCompareFunctionForArrayOfStrings', - suggestions: [ - { - desc: 'Add a comparator function to sort in ascending language-sensitive order', - output: 'const array = ["foo", "bar"]; array.sort((a, b) => a.localeCompare(b));', - }, - ], - }, - ], - }, - // optional chain - { - code: ` + errors: [ + { + messageId: 'provideCompareFunction', + suggestions: [], + }, + ], + }, + { + code: 'const array = ["foo", "bar"]; array.sort();', + errors: [ + { + messageId: 'provideCompareFunctionForArrayOfStrings', + suggestions: [ + { + desc: 'Add a comparator function to sort in ascending language-sensitive order', + output: + 'const array = ["foo", "bar"]; array.sort((a, b) => a.localeCompare(b));', + }, + ], + }, + ], + }, + // optional chain + { + code: ` function f(a: string[]) { a?.sort(); } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` ['foo', 'bar', 'baz'].sort(); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` function getString() { return 'foo'; } [getString(), getString()].sort(); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const foo = 'foo'; const bar = 'bar'; const baz = 'baz'; [foo, bar, baz].sort(); `, - errors: 1, - }, - ], - }, - ); + errors: 1, + }, + ], + }, + ); - ruleTester.run( - `A compare function should be provided when using "Array.prototype.toSorted()"`, - rule, - { - valid: [ - { - code: ` + ruleTester.run( + `A compare function should be provided when using "Array.prototype.toSorted()"`, + rule, + { + valid: [ + { + code: ` const arrayOfNumbers = [80, 3, 9, 34, 23, 5, 1]; const sortedArrayOfNumbers = arrayOfNumbers.toSorted((n, m) => n - m); `, - }, - { - code: `const sorted = unknownArrayType.toSorted();`, - }, - { - code: ` + }, + { + code: `const sorted = unknownArrayType.toSorted();`, + }, + { + code: ` function f(a: any[]) { return a.toSorted(undefined); } `, - }, - { - code: ` + }, + { + code: ` function f(a: any[]) { return a.toSorted((a, b) => a - b); } `, - }, - { - code: ` + }, + { + code: ` function f(a: Array) { return a.toSorted(undefined); } `, - }, - { - code: ` + }, + { + code: ` function f(a: Array) { return a.toSorted((a, b) => a - b); } `, - }, - { - code: ` + }, + { + code: ` function f(a: { toSorted(): void }) { return a.toSorted(); } `, - }, - { - code: ` + }, + { + code: ` class A { toSorted(): void {} } @@ -446,9 +448,9 @@ describe('S2871', () => { return a.toSorted(); } `, - }, - { - code: ` + }, + { + code: ` interface A { toSorted(): void; } @@ -456,9 +458,9 @@ describe('S2871', () => { return a.toSorted(); } `, - }, - { - code: ` + }, + { + code: ` interface A { toSorted(): void; } @@ -466,16 +468,16 @@ describe('S2871', () => { return a.toSorted(); } `, - }, - { - code: ` + }, + { + code: ` function f(a: any) { return a.toSorted(); } `, - }, - { - code: ` + }, + { + code: ` namespace UserDefined { interface Array { toSorted(): void; @@ -485,17 +487,17 @@ describe('S2871', () => { } } `, - }, - // optional chain - { - code: ` + }, + // optional chain + { + code: ` function f(a: any[]) { return a?.toSorted((a, b) => a - b); } `, - }, - { - code: ` + }, + { + code: ` namespace UserDefined { interface Array { toSorted(): void; @@ -505,113 +507,113 @@ describe('S2871', () => { } } `, - }, - { - code: `const sorted = Array.prototype.toSorted.apply([1, 2, 10])`, - }, - ], - invalid: [ - { - code: ` + }, + { + code: `const sorted = Array.prototype.toSorted.apply([1, 2, 10])`, + }, + ], + invalid: [ + { + code: ` var arrayOfNumbers = [80, 3, 9, 34, 23, 5, 1]; const sortedArrayOfNumbers = arrayOfNumbers.toSorted(); `, - errors: [ - { - message: `Provide a compare function to avoid sorting elements alphabetically.`, - line: 3, - column: 51, - endLine: 3, - endColumn: 59, - suggestions: [ - { - messageId: 'suggestNumericOrder', - output: ` + errors: [ + { + message: `Provide a compare function to avoid sorting elements alphabetically.`, + line: 3, + column: 51, + endLine: 3, + endColumn: 59, + suggestions: [ + { + messageId: 'suggestNumericOrder', + output: ` var arrayOfNumbers = [80, 3, 9, 34, 23, 5, 1]; const sortedArrayOfNumbers = arrayOfNumbers.toSorted((a, b) => (a - b)); `, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` var emptyArrayOfNumbers: number[] = []; const sortedEmptyArrayOfNumbers = emptyArrayOfNumbers.toSorted(); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` function getArrayOfNumbers(): number[] {} const sortedArrayOfNumbers = getArrayOfNumbers().toSorted(); `, - errors: 1, - }, - { - code: `const sortedArrayOfNumbers = [80, 3, 9, 34, 23, 5, 1].toSorted();`, - errors: [ - { - messageId: 'provideCompareFunction', - suggestions: [ - { - desc: 'Add a comparator function to sort in ascending order', - output: - 'const sortedArrayOfNumbers = [80, 3, 9, 34, 23, 5, 1].toSorted((a, b) => (a - b));', - }, - ], - }, - ], - }, - { - code: 'const sortedArrayOfNumbers = [Number("1"), Number("2"), Number("10")].toSorted();', - errors: [ - { - messageId: 'provideCompareFunction', - suggestions: [ - { - desc: 'Add a comparator function to sort in ascending order', - output: - 'const sortedArrayOfNumbers = [Number("1"), Number("2"), Number("10")].toSorted((a, b) => (a - b));', - }, - ], - }, - ], - }, - { - code: 'const sortedArrayOfNumbers = [Number("1"), 2, Number("10")].toSorted();', - errors: [ - { - messageId: 'provideCompareFunction', - suggestions: [ - { - desc: 'Add a comparator function to sort in ascending order', - output: - 'const sortedArrayOfNumbers = [Number("1"), 2, Number("10")].toSorted((a, b) => (a - b));', - }, - ], - }, - ], - }, - { - code: 'const sortedArrayOfNumbers = ["1", 2, "10"].toSorted();', - errors: [ - { - messageId: 'provideCompareFunction', - suggestions: [], - }, - ], - }, - { - code: `const sortedArrayOfNumbers = [80n, 3n, 9n, 34n, 23n, 5n, 1n].toSorted();`, - errors: [ - { - messageId: 'provideCompareFunction', - suggestions: [ - { - desc: 'Add a comparator function to sort in ascending order', - output: `const sortedArrayOfNumbers = [80n, 3n, 9n, 34n, 23n, 5n, 1n].toSorted((a, b) => { + errors: 1, + }, + { + code: `const sortedArrayOfNumbers = [80, 3, 9, 34, 23, 5, 1].toSorted();`, + errors: [ + { + messageId: 'provideCompareFunction', + suggestions: [ + { + desc: 'Add a comparator function to sort in ascending order', + output: + 'const sortedArrayOfNumbers = [80, 3, 9, 34, 23, 5, 1].toSorted((a, b) => (a - b));', + }, + ], + }, + ], + }, + { + code: 'const sortedArrayOfNumbers = [Number("1"), Number("2"), Number("10")].toSorted();', + errors: [ + { + messageId: 'provideCompareFunction', + suggestions: [ + { + desc: 'Add a comparator function to sort in ascending order', + output: + 'const sortedArrayOfNumbers = [Number("1"), Number("2"), Number("10")].toSorted((a, b) => (a - b));', + }, + ], + }, + ], + }, + { + code: 'const sortedArrayOfNumbers = [Number("1"), 2, Number("10")].toSorted();', + errors: [ + { + messageId: 'provideCompareFunction', + suggestions: [ + { + desc: 'Add a comparator function to sort in ascending order', + output: + 'const sortedArrayOfNumbers = [Number("1"), 2, Number("10")].toSorted((a, b) => (a - b));', + }, + ], + }, + ], + }, + { + code: 'const sortedArrayOfNumbers = ["1", 2, "10"].toSorted();', + errors: [ + { + messageId: 'provideCompareFunction', + suggestions: [], + }, + ], + }, + { + code: `const sortedArrayOfNumbers = [80n, 3n, 9n, 34n, 23n, 5n, 1n].toSorted();`, + errors: [ + { + messageId: 'provideCompareFunction', + suggestions: [ + { + desc: 'Add a comparator function to sort in ascending order', + output: `const sortedArrayOfNumbers = [80n, 3n, 9n, 34n, 23n, 5n, 1n].toSorted((a, b) => { if (a < b) { return -1; } else if (a > b) { @@ -620,138 +622,139 @@ describe('S2871', () => { return 0; } });`, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` var arrayOfObjects = [{a: 2}, {a: 4}]; const sortedArrayOfObject = arrayOfObjects.toSorted(); `, - errors: [ - { - messageId: 'provideCompareFunction', - suggestions: [], - }, - ], - }, - { - code: ` + errors: [ + { + messageId: 'provideCompareFunction', + suggestions: [], + }, + ], + }, + { + code: ` interface MyCustomNumber extends Number {} const arrayOfCustomNumbers: MyCustomNumber[]; const sortedArrayOfObject = arrayOfCustomNumbers.toSorted(); `, - errors: [ - { - messageId: 'provideCompareFunction', - suggestions: [], - }, - ], - }, - { - code: ` + errors: [ + { + messageId: 'provideCompareFunction', + suggestions: [], + }, + ], + }, + { + code: ` function f(a: Array) { return a.toSorted(); } `, - errors: [ - { - messageId: 'provideCompareFunction', - suggestions: [], - }, - ], - }, - { - code: ` + errors: [ + { + messageId: 'provideCompareFunction', + suggestions: [], + }, + ], + }, + { + code: ` function f(a: number[] | string[]) { return a.toSorted(); } `, - errors: [ - { - messageId: 'provideCompareFunction', - suggestions: [], - }, - ], - }, - { - code: ` + errors: [ + { + messageId: 'provideCompareFunction', + suggestions: [], + }, + ], + }, + { + code: ` function f(a: T) { return a.toSorted(); } `, - errors: [ - { - messageId: 'provideCompareFunction', - suggestions: [], - }, - ], - }, - { - code: ` + errors: [ + { + messageId: 'provideCompareFunction', + suggestions: [], + }, + ], + }, + { + code: ` function f(a: U) { return a.toSorted(); } `, - errors: [ - { - messageId: 'provideCompareFunction', - suggestions: [], - }, - ], - }, - { - code: 'const array = ["foo", "bar"]; const sortedArray = array.toSorted();', - errors: [ - { - message: - 'Provide a compare function that depends on "String.localeCompare", to reliably sort elements alphabetically.', - suggestions: [ - { - desc: 'Add a comparator function to sort in ascending language-sensitive order', - output: - 'const array = ["foo", "bar"]; const sortedArray = array.toSorted((a, b) => a.localeCompare(b));', - }, - ], - }, - ], - }, - // optional chain - { - code: ` + errors: [ + { + messageId: 'provideCompareFunction', + suggestions: [], + }, + ], + }, + { + code: 'const array = ["foo", "bar"]; const sortedArray = array.toSorted();', + errors: [ + { + message: + 'Provide a compare function that depends on "String.localeCompare", to reliably sort elements alphabetically.', + suggestions: [ + { + desc: 'Add a comparator function to sort in ascending language-sensitive order', + output: + 'const array = ["foo", "bar"]; const sortedArray = array.toSorted((a, b) => a.localeCompare(b));', + }, + ], + }, + ], + }, + // optional chain + { + code: ` function f(a: string[]) { return a?.toSorted(); } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const sorted = ['foo', 'bar', 'baz'].toSorted(); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` function getString() { return 'foo'; } const sorted = [getString(), getString()].toSorted(); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const foo = 'foo'; const bar = 'bar'; const baz = 'baz'; const sorted = [foo, bar, baz].toSorted(); `, - errors: 1, - }, - ], - }, - ); + errors: 1, + }, + ], + }, + ); + }); }); diff --git a/packages/jsts/src/rules/S2990/unit.test.ts b/packages/jsts/src/rules/S2990/unit.test.ts index a1b16c4122..83e4b9a03e 100644 --- a/packages/jsts/src/rules/S2990/unit.test.ts +++ b/packages/jsts/src/rules/S2990/unit.test.ts @@ -16,36 +16,37 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2990', () => { - const ruleTesterJS = new RuleTester(); - const ruleTesterTS = new RuleTester(); + it('S2990', () => { + const ruleTesterJS = new RuleTester(); + const ruleTesterTS = new RuleTester(); - const testCases = { - valid: [ - { - code: `console.log(this);`, - }, - { - code: ` + const testCases = { + valid: [ + { + code: `console.log(this);`, + }, + { + code: ` function foo() { x = this.a // OK var func = s => this.foo(s) // OK var func1 = s => {return this.foo(s)} // OK }`, - }, - { - code: ` + }, + { + code: ` var foo = function(){ foo(this) }`, - }, - { - code: `var func = s => this.foo(s)`, - }, - { - code: ` + }, + { + code: `var func = s => this.foo(s)`, + }, + { + code: ` class C { constructor() { this.a = []; // ok @@ -63,106 +64,107 @@ describe('S2990', () => { this.id = foo; // ok } }`, - }, - ], - invalid: [ - { - code: `console.log(this.prop);`, - errors: [ - { - message: `Remove the use of "this".`, - line: 1, - endLine: 1, - column: 13, - endColumn: 17, - suggestions: [ - { - output: 'console.log(prop);', - desc: 'Remove "this"', - }, - { - output: 'console.log(window.prop);', - desc: 'Replace "this" with "window" object', - }, - ], - }, - ], - }, - { - code: `this.a = function(){}`, - errors: 1, - }, - { - code: `var x = this.a()`, - errors: 1, - }, - { - code: ` + }, + ], + invalid: [ + { + code: `console.log(this.prop);`, + errors: [ + { + message: `Remove the use of "this".`, + line: 1, + endLine: 1, + column: 13, + endColumn: 17, + suggestions: [ + { + output: 'console.log(prop);', + desc: 'Remove "this"', + }, + { + output: 'console.log(window.prop);', + desc: 'Replace "this" with "window" object', + }, + ], + }, + ], + }, + { + code: `this.a = function(){}`, + errors: 1, + }, + { + code: `var x = this.a()`, + errors: 1, + }, + { + code: ` if (!this.JSON) { this.JSON = {} }`, - errors: 2, - }, - { - code: `this.foo = bar;`, - errors: [ - { - message: `Remove the use of "this".`, - suggestions: [ - { - desc: 'Remove "this"', - output: 'foo = bar;', - }, - { - desc: 'Replace "this" with "window" object', - output: 'window.foo = bar;', - }, - ], - }, - ], - }, - { - code: `this.foo.bar.baz = qux;`, - errors: [ - { - message: `Remove the use of "this".`, - suggestions: [ - { - desc: 'Remove "this"', - output: 'foo.bar.baz = qux;', - }, - { - desc: 'Replace "this" with "window" object', - output: 'window.foo.bar.baz = qux;', - }, - ], - }, - ], - }, - { - code: `this['f' + 'o' + 'o'] = bar;`, - errors: [ - { - message: `Remove the use of "this".`, - suggestions: [], - }, - ], - }, - ], - }; + errors: 2, + }, + { + code: `this.foo = bar;`, + errors: [ + { + message: `Remove the use of "this".`, + suggestions: [ + { + desc: 'Remove "this"', + output: 'foo = bar;', + }, + { + desc: 'Replace "this" with "window" object', + output: 'window.foo = bar;', + }, + ], + }, + ], + }, + { + code: `this.foo.bar.baz = qux;`, + errors: [ + { + message: `Remove the use of "this".`, + suggestions: [ + { + desc: 'Remove "this"', + output: 'foo.bar.baz = qux;', + }, + { + desc: 'Replace "this" with "window" object', + output: 'window.foo.bar.baz = qux;', + }, + ], + }, + ], + }, + { + code: `this['f' + 'o' + 'o'] = bar;`, + errors: [ + { + message: `Remove the use of "this".`, + suggestions: [], + }, + ], + }, + ], + }; - ruleTesterJS.run('The global "this" object should not be used JavaScript', rule, testCases); - testCases.valid.push({ - code: ` + ruleTesterJS.run('The global "this" object should not be used JavaScript', rule, testCases); + testCases.valid.push({ + code: ` class C { prop = this.C }`, - }); - testCases.valid.push({ - code: ` + }); + testCases.valid.push({ + code: ` const c = class C { prop = this.C }`, + }); + ruleTesterTS.run('The global "this" object should not be used TypeScript', rule, testCases); }); - ruleTesterTS.run('The global "this" object should not be used TypeScript', rule, testCases); }); diff --git a/packages/jsts/src/rules/S2999/unit.test.ts b/packages/jsts/src/rules/S2999/unit.test.ts index 0ff3c15742..95985f4237 100644 --- a/packages/jsts/src/rules/S2999/unit.test.ts +++ b/packages/jsts/src/rules/S2999/unit.test.ts @@ -16,176 +16,178 @@ */ import { rule } from './index.js'; import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S2999', () => { - const ruleTesterJs = new DefaultParserRuleTester(); - ruleTesterJs.run('"new" operators should be used with functions [js]', rule, { - valid: [ - { - code: `new 'str'; // not reported without type information`, - options: [{ considerJSDoc: false }], - }, - ], - invalid: [], - }); + it('S2999', () => { + const ruleTesterJs = new DefaultParserRuleTester(); + ruleTesterJs.run('"new" operators should be used with functions [js]', rule, { + valid: [ + { + code: `new 'str'; // not reported without type information`, + options: [{ considerJSDoc: false }], + }, + ], + invalid: [], + }); - const ruleTester = new RuleTester(); - ruleTester.run(`"new" operators should be used with functions [ts]`, rule, { - valid: [ - { - code: `new Promise(function (resolve, reject) {});`, - options: [{ considerJSDoc: false }], - }, - { - code: `new Error('Whoops!')`, - options: [{ considerJSDoc: false }], - }, - { - code: ` + const ruleTester = new RuleTester(); + ruleTester.run(`"new" operators should be used with functions [ts]`, rule, { + valid: [ + { + code: `new Promise(function (resolve, reject) {});`, + options: [{ considerJSDoc: false }], + }, + { + code: `new Error('Whoops!')`, + options: [{ considerJSDoc: false }], + }, + { + code: ` class MyClass {} new MyClass(); `, - options: [{ considerJSDoc: false }], - }, - { - code: ` + options: [{ considerJSDoc: false }], + }, + { + code: ` class MyClass { static createInstance() { return new this(); } } `, - options: [{ considerJSDoc: false }], - }, - { - code: ` + options: [{ considerJSDoc: false }], + }, + { + code: ` class A {} class B {} let klass: {new(): A}|{new(): B}; new klass; `, - options: [{ considerJSDoc: false }], - }, - { - code: ` + options: [{ considerJSDoc: false }], + }, + { + code: ` function MyClass() {} new MyClass(); `, - options: [{ considerJSDoc: false }], - }, - { - code: ` + options: [{ considerJSDoc: false }], + }, + { + code: ` function MyClass() {} var MyClass1 = MyClass; new MyClass1(); `, - options: [{ considerJSDoc: false }], - }, - { - code: ` + options: [{ considerJSDoc: false }], + }, + { + code: ` /** * @constructor */ function MyClass() {} new MyClass(); `, - options: [{ considerJSDoc: false }], - }, - { - code: ` + options: [{ considerJSDoc: false }], + }, + { + code: ` /** * @class */ function MyClass() {} new MyClass(); `, - options: [{ considerJSDoc: false }], - }, - { - code: ` + options: [{ considerJSDoc: false }], + }, + { + code: ` /** * @class */ function MyClass() {} new MyClass(); `, - options: [{ considerJSDoc: true }], - }, - { - code: ` + options: [{ considerJSDoc: true }], + }, + { + code: ` let Str: new (s: string) => string; new Str('hello') `, - options: [{ considerJSDoc: false }], - }, - { - code: `new any;`, - options: [{ considerJSDoc: false }], - }, - ], - invalid: [ - { - code: ` + options: [{ considerJSDoc: false }], + }, + { + code: `new any;`, + options: [{ considerJSDoc: false }], + }, + ], + invalid: [ + { + code: ` var numeric = 1; new numeric; `, - errors: [ - { - message: `{\"message\":\"Replace numeric with a constructor function.\",\"secondaryLocations\":[{\"column\":8,\"line\":3,\"endColumn\":11,\"endLine\":3}]}`, - line: 3, - column: 13, - endLine: 3, - endColumn: 20, - }, - ], - options: [{ considerJSDoc: false }, 'sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: `{\"message\":\"Replace numeric with a constructor function.\",\"secondaryLocations\":[{\"column\":8,\"line\":3,\"endColumn\":11,\"endLine\":3}]}`, + line: 3, + column: 13, + endLine: 3, + endColumn: 20, + }, + ], + options: [{ considerJSDoc: false }, 'sonar-runtime'], + }, + { + code: ` var boolean = true; new boolean; `, - errors: 1, - options: [{ considerJSDoc: false }], - }, - { - code: ` + errors: 1, + options: [{ considerJSDoc: false }], + }, + { + code: ` var string = 'str'; new string; `, - errors: 1, - options: [{ considerJSDoc: false }], - }, - { - code: ` + errors: 1, + options: [{ considerJSDoc: false }], + }, + { + code: ` var object = { a:1 }; new object; `, - errors: 1, - options: [{ considerJSDoc: false }], - }, - { - code: ` + errors: 1, + options: [{ considerJSDoc: false }], + }, + { + code: ` function MyClass() {} new MyClass(); `, - errors: 1, - options: [{ considerJSDoc: true }], - }, - { - code: `new function(){ return 5; };`, - errors: [ - { - message: `{\"message\":\"Replace this function with a constructor function.\",\"secondaryLocations\":[{\"column\":0,\"line\":1,\"endColumn\":3,\"endLine\":1}]}`, - line: 1, - column: 5, - endLine: 1, - endColumn: 13, - }, - ], - options: [{ considerJSDoc: true }, 'sonar-runtime'], - }, - ], + errors: 1, + options: [{ considerJSDoc: true }], + }, + { + code: `new function(){ return 5; };`, + errors: [ + { + message: `{\"message\":\"Replace this function with a constructor function.\",\"secondaryLocations\":[{\"column\":0,\"line\":1,\"endColumn\":3,\"endLine\":1}]}`, + line: 1, + column: 5, + endLine: 1, + endColumn: 13, + }, + ], + options: [{ considerJSDoc: true }, 'sonar-runtime'], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3001/unit.test.ts b/packages/jsts/src/rules/S3001/unit.test.ts index d1d04412c8..e048e9588e 100644 --- a/packages/jsts/src/rules/S3001/unit.test.ts +++ b/packages/jsts/src/rules/S3001/unit.test.ts @@ -16,94 +16,96 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3001', () => { - const tests = { - valid: [ - { - code: ` + it('S3001', () => { + const tests = { + valid: [ + { + code: ` var obj = { a: 1, b: 1}; delete obj.a;`, - }, - { - code: ` + }, + { + code: ` var obj = { a: 1, b: 1}; delete obj['a'];`, - }, - { - code: ` + }, + { + code: ` var arr = [1, 2]; delete arr[0];`, - }, - { - code: ` + }, + { + code: ` var arr = [1, 2]; var idx = 0; delete arr[idx];`, - }, - { - code: ` + }, + { + code: ` glob = 5; delete glob; `, - }, - { - code: ` + }, + { + code: ` fun = function () {}; delete fun; `, - }, - { - code: ` + }, + { + code: ` var obj = { a: possiblyUndefined() }; delete obj?.a;`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` var v = 1; delete v;`, - errors: [ - { - message: `Remove this "delete" operator or pass an object property to it.`, - line: 3, - endLine: 3, - column: 9, - endColumn: 17, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Remove this "delete" operator or pass an object property to it.`, + line: 3, + endLine: 3, + column: 9, + endColumn: 17, + }, + ], + }, + { + code: ` function fun(p) { delete p; }`, - errors: 1, - }, - { - code: `delete foo().bar();`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: `delete foo().bar();`, + errors: 1, + }, + { + code: ` var v = 1; delete v + 1;`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` var obj = { a: 1, b: 2}; delete obj;`, - errors: 1, - }, - ], - }; + errors: 1, + }, + ], + }; - const ruleTesterJs = new RuleTester(); - const ruleTesterTs = new RuleTester(); + const ruleTesterJs = new RuleTester(); + const ruleTesterTs = new RuleTester(); - ruleTesterJs.run('"delete" should be used only with object properties [js]', rule, tests); - ruleTesterTs.run('"delete" should be used only with object properties [ts]', rule, tests); + ruleTesterJs.run('"delete" should be used only with object properties [js]', rule, tests); + ruleTesterTs.run('"delete" should be used only with object properties [ts]', rule, tests); + }); }); diff --git a/packages/jsts/src/rules/S3003/unit.test.ts b/packages/jsts/src/rules/S3003/unit.test.ts index 24b7877127..7bbef3aa76 100644 --- a/packages/jsts/src/rules/S3003/unit.test.ts +++ b/packages/jsts/src/rules/S3003/unit.test.ts @@ -16,101 +16,103 @@ */ import { rule } from './index.js'; import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3003', () => { - const ruleTesterJs = new DefaultParserRuleTester(); - ruleTesterJs.run('Comparison operators should not be used with strings [js]', rule, { - valid: [ - { - code: ` + it('S3003', () => { + const ruleTesterJs = new DefaultParserRuleTester(); + ruleTesterJs.run('Comparison operators should not be used with strings [js]', rule, { + valid: [ + { + code: ` let str1 = 'hello', str2 = 'world'; str1 < str2; // not reported without type information`, - }, - ], - invalid: [], - }); + }, + ], + invalid: [], + }); - const ruleTesterTs = new RuleTester(); - ruleTesterTs.run(`Comparison operators should not be used with strings [ts]`, rule, { - valid: [ - { - code: ` + const ruleTesterTs = new RuleTester(); + ruleTesterTs.run(`Comparison operators should not be used with strings [ts]`, rule, { + valid: [ + { + code: ` let str1 = 'hello', str2 = 'world'; str1 == str2;`, - }, - { - code: ` + }, + { + code: ` let str = 'hello', num = 5; str < num;`, - }, - { - code: ` + }, + { + code: ` let str = 'hello', num = 5; num < str;`, - }, - { - code: ` + }, + { + code: ` let str = 'hello'; str < 'h';`, - }, - { - code: ` + }, + { + code: ` let str = 'hello'; 'h' < str;`, - }, - { - code: ` + }, + { + code: ` ['foo', 'bar', 'baz'].sort((a, b) => a < b); `, - }, - { - code: ` + }, + { + code: ` sort((a: string, b: string) => a < b) `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` let str1 = 'hello', str2 = 'world'; str1 < str2;`, - options: ['sonar-runtime'], - errors: [ - { - message: - '{"message":"Convert operands of this use of \\"<\\" to number type.","secondaryLocations":[{"column":8,"line":3,"endColumn":12,"endLine":3},{"column":15,"line":3,"endColumn":19,"endLine":3}]}', - line: 3, - column: 14, - endLine: 3, - endColumn: 15, - }, - ], - }, - { - code: ` + options: ['sonar-runtime'], + errors: [ + { + message: + '{"message":"Convert operands of this use of \\"<\\" to number type.","secondaryLocations":[{"column":8,"line":3,"endColumn":12,"endLine":3},{"column":15,"line":3,"endColumn":19,"endLine":3}]}', + line: 3, + column: 14, + endLine: 3, + endColumn: 15, + }, + ], + }, + { + code: ` let str1 = 'hello', str2 = 'world'; str1 <= str2;`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` let str1 = 'hello', str2 = 'world'; str1 > str2;`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` let str1 = 'hello', str2 = 'world'; str1 >= str2;`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` (function () {})((a: string, b: string) => a < b) `, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3317/unit.test.ts b/packages/jsts/src/rules/S3317/unit.test.ts index e25bce8535..7a24ec3e67 100644 --- a/packages/jsts/src/rules/S3317/unit.test.ts +++ b/packages/jsts/src/rules/S3317/unit.test.ts @@ -17,161 +17,163 @@ import { NoTypeCheckingRuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; import path from 'path'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3317', () => { - const ruleTester = new NoTypeCheckingRuleTester(); + it('S3317', () => { + const ruleTester = new NoTypeCheckingRuleTester(); - ruleTester.run('Class names and file names should match', rule, { - valid: [ - { - code: `class MyClass {} + ruleTester.run('Class names and file names should match', rule, { + valid: [ + { + code: `class MyClass {} export default MyClass;`, - filename: 'MyClass.js', - }, - { - code: `class MyClass {} + filename: 'MyClass.js', + }, + { + code: `class MyClass {} export default MySuperClass;`, - filename: 'my-super-class.js', - }, - { - code: `class MyClass {} + filename: 'my-super-class.js', + }, + { + code: `class MyClass {} export default MyClass;`, - filename: 'my_class.js', - }, - { - code: `class MyClass1 {} + filename: 'my_class.js', + }, + { + code: `class MyClass1 {} export default MyClass1;`, - filename: 'myclass1.js', - }, - { - code: `function MyFunction() {} + filename: 'myclass1.js', + }, + { + code: `function MyFunction() {} export default MyFunction;`, - filename: 'MyFunction.js', - }, - { - code: `const myConst = 3.14 + filename: 'MyFunction.js', + }, + { + code: `const myConst = 3.14 export default myConst;`, - filename: 'myConst.js', - }, - { - code: `class MyClass {} + filename: 'myConst.js', + }, + { + code: `class MyClass {} export default MyClass; export function foo() {}`, - filename: 'ok_several_exports.js', - }, - { - code: `export default class {}`, - filename: 'ok_anonymous_class.js', - }, - { - code: `export default 42;`, - filename: 'ok_anonymous_constant.js', - }, - { - code: `export default function () {}`, - filename: 'ok_anonymous_function.js', - }, - { - code: `const pi = 3.14; + filename: 'ok_several_exports.js', + }, + { + code: `export default class {}`, + filename: 'ok_anonymous_class.js', + }, + { + code: `export default 42;`, + filename: 'ok_anonymous_constant.js', + }, + { + code: `export default function () {}`, + filename: 'ok_anonymous_function.js', + }, + { + code: `const pi = 3.14; export default pi * 42;`, - filename: 'ok_expression.js', - }, - { - code: `const myConst = 3.14; + filename: 'ok_expression.js', + }, + { + code: `const myConst = 3.14; export default myConst;`, - filename: 'index.js', //ignore index.js - }, - { - code: `let myConst = 3.14; + filename: 'index.js', //ignore index.js + }, + { + code: `let myConst = 3.14; export default myConst;`, //Not a const - filename: 'nok_constant.js', - }, - { - code: `class MyClass {} + filename: 'nok_constant.js', + }, + { + code: `class MyClass {} export default MyClass;`, - filename: `${import.meta.dirname}${path.sep}MyClass.js`, - }, - { - code: `const MY_CONST = 3.14; + filename: `${import.meta.dirname}${path.sep}MyClass.js`, + }, + { + code: `const MY_CONST = 3.14; export default MY_CONST;`, - filename: 'MY_CONST.js', - }, - { - code: `class MyClass {} + filename: 'MY_CONST.js', + }, + { + code: `class MyClass {} export default MyClass;`, - filename: 'my.class.js', - }, - { - code: `class MyClass {} + filename: 'my.class.js', + }, + { + code: `class MyClass {} export default MyClass;`, - filename: 'MyClass.dev.js', //ignore postfix - }, - ], - invalid: [ - { - code: `foo(); + filename: 'MyClass.dev.js', //ignore postfix + }, + ], + invalid: [ + { + code: `foo(); function myFunc () {} export default myFunc;`, - filename: 'nok_function_export.js', - errors: [ - { - message: 'Rename this file to "myFunc"', - line: 0, - column: 1, - }, - ], - }, - { - code: `class MyClass {} + filename: 'nok_function_export.js', + errors: [ + { + message: 'Rename this file to "myFunc"', + line: 0, + column: 1, + }, + ], + }, + { + code: `class MyClass {} export default MyClass;`, - filename: 'nok_identifier.js', - errors: [ - { - message: 'Rename this file to "MyClass"', - }, - ], - }, + filename: 'nok_identifier.js', + errors: [ + { + message: 'Rename this file to "MyClass"', + }, + ], + }, - { - code: `export default class MyClass {}`, - filename: 'nok_class_declaration.js', - errors: [ - { - message: 'Rename this file to "MyClass"', - }, - ], - }, + { + code: `export default class MyClass {}`, + filename: 'nok_class_declaration.js', + errors: [ + { + message: 'Rename this file to "MyClass"', + }, + ], + }, - { - code: `export default function MyFunction() {};`, - filename: 'nok_MyFunction.js', - errors: [ - { - message: 'Rename this file to "MyFunction"', - }, - ], - }, - { - code: `const myConst = 3.14; + { + code: `export default function MyFunction() {};`, + filename: 'nok_MyFunction.js', + errors: [ + { + message: 'Rename this file to "MyFunction"', + }, + ], + }, + { + code: `const myConst = 3.14; export default myConst;`, - filename: 'nok_constant.js', - errors: [ - { - message: 'Rename this file to "myConst"', - }, - ], - }, - { - code: `const myConst = 3.14; + filename: 'nok_constant.js', + errors: [ + { + message: 'Rename this file to "myConst"', + }, + ], + }, + { + code: `const myConst = 3.14; export default myConst;`, - filename: 'no_extension', - errors: [ - { - message: 'Rename this file to "myConst"', - }, - ], - }, - ], + filename: 'no_extension', + errors: [ + { + message: 'Rename this file to "myConst"', + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3330/unit.test.ts b/packages/jsts/src/rules/S3330/unit.test.ts index c30ce70326..e1e6c14e04 100644 --- a/packages/jsts/src/rules/S3330/unit.test.ts +++ b/packages/jsts/src/rules/S3330/unit.test.ts @@ -17,33 +17,34 @@ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3330', () => { - const ruleTesterJs = new RuleTester(); - const ruleTesterTs = new RuleTester(); + it('S3330', () => { + const ruleTesterJs = new RuleTester(); + const ruleTesterTs = new RuleTester(); - const cookieSessionTestCases = { - valid: [ - { - code: ` + const cookieSessionTestCases = { + valid: [ + { + code: ` var cookieSession = require('cookie-session'); var session1 = cookieSession({ secret: "ddfdsfd", httpOnly: true, }); `, - }, - { - code: ` + }, + { + code: ` var cookieSession = require('cookie-session'); var session1 = cookieSession({ secret: "ddfdsfd", }); // Compliant: by default httpOnly is set to true on https connection `, - }, - { - code: ` + }, + { + code: ` var cookieSession = require('cookie-session'); var session1 = cookieSession("wrong argument"); var session1 = cookieSession(); @@ -56,31 +57,31 @@ describe('S3330', () => { httpOnly: httpOnlyValue, }); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` var cookieSession = require('cookie-session'); var session1 = cookieSession({ secret: "ddfdsfd", httpOnly: false, }); `, - errors: [ - { - message: - '{"message":"Make sure creating this cookie without the \\"httpOnly\\" flag is safe.","secondaryLocations":[{"column":18,"line":5,"endColumn":23,"endLine":5}]}', - line: 3, - endLine: 3, - column: 22, - endColumn: 35, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: + '{"message":"Make sure creating this cookie without the \\"httpOnly\\" flag is safe.","secondaryLocations":[{"column":18,"line":5,"endColumn":23,"endLine":5}]}', + line: 3, + endLine: 3, + column: 22, + endColumn: 35, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` var cookieSession = require('cookie-session'); const options = { secret: "ddfdsfd", @@ -88,20 +89,20 @@ describe('S3330', () => { }; var session1 = cookieSession(options); `, - errors: [ - { - message: - '{"message":"Make sure creating this cookie without the \\"httpOnly\\" flag is safe.","secondaryLocations":[{"column":18,"line":5,"endColumn":23,"endLine":5},{"column":22,"line":3,"endColumn":7,"endLine":6}]}', - line: 7, - endLine: 7, - column: 22, - endColumn: 35, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: + '{"message":"Make sure creating this cookie without the \\"httpOnly\\" flag is safe.","secondaryLocations":[{"column":18,"line":5,"endColumn":23,"endLine":5},{"column":22,"line":3,"endColumn":7,"endLine":6}]}', + line: 7, + endLine: 7, + column: 22, + endColumn: 35, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` var cookieSession = require('cookie-session'); const ishttpOnly = false; const options = { @@ -110,25 +111,25 @@ describe('S3330', () => { }; var session1 = cookieSession(options); `, - errors: [ - { - message: - '{"message":"Make sure creating this cookie without the \\"httpOnly\\" flag is safe.","secondaryLocations":[{"column":25,"line":3,"endColumn":30,"endLine":3},{"column":22,"line":4,"endColumn":7,"endLine":7}]}', - line: 8, - endLine: 8, - column: 22, - endColumn: 35, - }, - ], - options: ['sonar-runtime'], - }, - ], - }; + errors: [ + { + message: + '{"message":"Make sure creating this cookie without the \\"httpOnly\\" flag is safe.","secondaryLocations":[{"column":25,"line":3,"endColumn":30,"endLine":3},{"column":22,"line":4,"endColumn":7,"endLine":7}]}', + line: 8, + endLine: 8, + column: 22, + endColumn: 35, + }, + ], + options: ['sonar-runtime'], + }, + ], + }; - const cookiesTestCases = { - valid: [ - { - code: ` + const cookiesTestCases = { + valid: [ + { + code: ` var Cookies = require('cookies'); var cookies = new Cookies(req, res, { @@ -139,9 +140,9 @@ describe('S3330', () => { }); // Compliant: by default httpOnly is set to true on https connection cookies.set('LastVisit', new Date().toISOString(), { signed: true }); `, - }, - { - code: ` + }, + { + code: ` var Cookies = require('cookies') var cookies = new Cookies(req, res, { @@ -153,9 +154,9 @@ describe('S3330', () => { httpOnly: true }); `, - }, - { - code: ` + }, + { + code: ` var Cookies = require('cookies') var cookies = new Cookies(req, res, { @@ -174,11 +175,11 @@ describe('S3330', () => { httpOnly: httpOnlyValue }); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` var Cookies = require('cookies'); var cookies = new Cookies(req, res, { keys: keys }); cookies.set('LastVisit', new Date().toISOString(), { @@ -186,20 +187,20 @@ describe('S3330', () => { httpOnly: false }); `, - errors: [ - { - message: - '{"message":"Make sure creating this cookie without the \\"httpOnly\\" flag is safe.","secondaryLocations":[{"column":18,"line":6,"endColumn":23,"endLine":6}]}', - line: 4, - endLine: 4, - column: 7, - endColumn: 18, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: + '{"message":"Make sure creating this cookie without the \\"httpOnly\\" flag is safe.","secondaryLocations":[{"column":18,"line":6,"endColumn":23,"endLine":6}]}', + line: 4, + endLine: 4, + column: 7, + endColumn: 18, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` var Cookies = require('cookies'); var cookies = new Cookies(req, res, { keys: keys }); var options = { @@ -208,20 +209,20 @@ describe('S3330', () => { }; cookies.set('LastVisit', new Date().toISOString(), options); `, - errors: [ - { - message: - '{"message":"Make sure creating this cookie without the \\"httpOnly\\" flag is safe.","secondaryLocations":[{"column":18,"line":6,"endColumn":23,"endLine":6},{"column":20,"line":4,"endColumn":7,"endLine":7}]}', - line: 8, - endLine: 8, - column: 7, - endColumn: 18, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: + '{"message":"Make sure creating this cookie without the \\"httpOnly\\" flag is safe.","secondaryLocations":[{"column":18,"line":6,"endColumn":23,"endLine":6},{"column":20,"line":4,"endColumn":7,"endLine":7}]}', + line: 8, + endLine: 8, + column: 7, + endColumn: 18, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` var Cookies = require('cookies'); var cookies = new Cookies(req, res, { keys: keys }); var httpOnly = false; @@ -231,31 +232,31 @@ describe('S3330', () => { }; cookies.set('LastVisit', new Date().toISOString(), options); `, - errors: [ - { - message: - '{"message":"Make sure creating this cookie without the \\"httpOnly\\" flag is safe.","secondaryLocations":[{"column":21,"line":4,"endColumn":26,"endLine":4},{"column":20,"line":5,"endColumn":7,"endLine":8}]}', - line: 9, - endLine: 9, - column: 7, - endColumn: 18, - }, - ], - options: ['sonar-runtime'], - }, - ], - }; + errors: [ + { + message: + '{"message":"Make sure creating this cookie without the \\"httpOnly\\" flag is safe.","secondaryLocations":[{"column":21,"line":4,"endColumn":26,"endLine":4},{"column":20,"line":5,"endColumn":7,"endLine":8}]}', + line: 9, + endLine: 9, + column: 7, + endColumn: 18, + }, + ], + options: ['sonar-runtime'], + }, + ], + }; - const csurfTestCases = { - valid: [ - { - code: ` + const csurfTestCases = { + valid: [ + { + code: ` var csrf = require('csurf'); var csrfProtection = csrf({ cookie: { httpOnly: true }}); `, - }, - { - code: ` + }, + { + code: ` var csrf = require('csurf'); var csrfProtection = csrf("unknown argument"); var csrfProtection = csrf({ cookie: "unknown"}); @@ -272,68 +273,68 @@ describe('S3330', () => { } var csrfProtection = csrf({ cookie: cookieValues}); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` var csrf = require('csurf'); var csrfProtection = csrf({ cookie: { httpOnly: false }}); // Sensitive `, - errors: [ - { - message: - '{"message":"Make sure creating this cookie without the \\"httpOnly\\" flag is safe.","secondaryLocations":[{"column":54,"line":3,"endColumn":59,"endLine":3}]}', - line: 3, - endLine: 3, - column: 28, - endColumn: 32, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: + '{"message":"Make sure creating this cookie without the \\"httpOnly\\" flag is safe.","secondaryLocations":[{"column":54,"line":3,"endColumn":59,"endLine":3}]}', + line: 3, + endLine: 3, + column: 28, + endColumn: 32, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` var csrf = require('csurf'); var cookieObject = {cookie: {httpOnly : false}}; var csrfProtection = csrf(cookieObject); // Sensitive `, - errors: [ - { - message: - '{"message":"Make sure creating this cookie without the \\"httpOnly\\" flag is safe.","secondaryLocations":[{"column":46,"line":3,"endColumn":51,"endLine":3},{"column":25,"line":3,"endColumn":53,"endLine":3}]}', - line: 4, - endLine: 4, - column: 28, - endColumn: 32, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: + '{"message":"Make sure creating this cookie without the \\"httpOnly\\" flag is safe.","secondaryLocations":[{"column":46,"line":3,"endColumn":51,"endLine":3},{"column":25,"line":3,"endColumn":53,"endLine":3}]}', + line: 4, + endLine: 4, + column: 28, + endColumn: 32, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` var csrf = require('csurf'); var csrfProtection = csrf({ cookie: true}); // Sensitive `, - errors: [ - { - message: - '{"message":"Make sure creating this cookie without the \\"httpOnly\\" flag is safe.","secondaryLocations":[{"column":42,"line":3,"endColumn":46,"endLine":3}]}', - line: 3, - endLine: 3, - column: 28, - endColumn: 32, - }, - ], - options: ['sonar-runtime'], - }, - ], - }; + errors: [ + { + message: + '{"message":"Make sure creating this cookie without the \\"httpOnly\\" flag is safe.","secondaryLocations":[{"column":42,"line":3,"endColumn":46,"endLine":3}]}', + line: 3, + endLine: 3, + column: 28, + endColumn: 32, + }, + ], + options: ['sonar-runtime'], + }, + ], + }; - const expressSessionTestCases = { - valid: [ - { - code: ` + const expressSessionTestCases = { + valid: [ + { + code: ` var express = require('express'); var session = require('express-session'); @@ -349,9 +350,9 @@ describe('S3330', () => { } })) // Compliant: by default httpOnly is set to true on https `, - }, - { - code: ` + }, + { + code: ` var express = require('express'); var session = require('express-session'); @@ -368,9 +369,9 @@ describe('S3330', () => { } })); `, - }, - { - code: ` + }, + { + code: ` var express = require('express'); var session = require('express-session'); @@ -392,11 +393,11 @@ describe('S3330', () => { cookie: cookieValue })); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` var express = require('express'); var session = require('express-session'); @@ -413,52 +414,53 @@ describe('S3330', () => { } })); `, - errors: 1, - }, - ], - }; + errors: 1, + }, + ], + }; - ruleTesterJs.run( - '[JS express-session] Creating cookies without the "httpOnly" flag is security-sensitive', - rule, - expressSessionTestCases, - ); - ruleTesterTs.run( - '[TS express-session] Creating cookies without the "httpOnly" flag is security-sensitive', - rule, - expressSessionTestCases, - ); + ruleTesterJs.run( + '[JS express-session] Creating cookies without the "httpOnly" flag is security-sensitive', + rule, + expressSessionTestCases, + ); + ruleTesterTs.run( + '[TS express-session] Creating cookies without the "httpOnly" flag is security-sensitive', + rule, + expressSessionTestCases, + ); - ruleTesterJs.run( - '[JS cookie-session] Creating cookies without the "httpOnly" flag is security-sensitive', - rule, - cookieSessionTestCases, - ); - ruleTesterTs.run( - '[TS cookie-session] Creating cookies without the "httpOnly" flag is security-sensitive', - rule, - cookieSessionTestCases, - ); + ruleTesterJs.run( + '[JS cookie-session] Creating cookies without the "httpOnly" flag is security-sensitive', + rule, + cookieSessionTestCases, + ); + ruleTesterTs.run( + '[TS cookie-session] Creating cookies without the "httpOnly" flag is security-sensitive', + rule, + cookieSessionTestCases, + ); - ruleTesterJs.run( - '[JS cookies] Creating cookies without the "httpOnly" flag is security-sensitive', - rule, - cookiesTestCases, - ); - ruleTesterTs.run( - '[TS cookies] Creating cookies without the "httpOnly" flag is security-sensitive', - rule, - cookiesTestCases, - ); + ruleTesterJs.run( + '[JS cookies] Creating cookies without the "httpOnly" flag is security-sensitive', + rule, + cookiesTestCases, + ); + ruleTesterTs.run( + '[TS cookies] Creating cookies without the "httpOnly" flag is security-sensitive', + rule, + cookiesTestCases, + ); - ruleTesterJs.run( - '[JS csurf] Creating cookies without the "httpOnly" flag is security-sensitive', - rule, - csurfTestCases, - ); - ruleTesterTs.run( - '[TS csurf] Creating cookies without the "httpOnly" flag is security-sensitive', - rule, - csurfTestCases, - ); + ruleTesterJs.run( + '[JS csurf] Creating cookies without the "httpOnly" flag is security-sensitive', + rule, + csurfTestCases, + ); + ruleTesterTs.run( + '[TS csurf] Creating cookies without the "httpOnly" flag is security-sensitive', + rule, + csurfTestCases, + ); + }); }); diff --git a/packages/jsts/src/rules/S3358/unit.test.ts b/packages/jsts/src/rules/S3358/unit.test.ts index e217203efb..5e2c780e0f 100644 --- a/packages/jsts/src/rules/S3358/unit.test.ts +++ b/packages/jsts/src/rules/S3358/unit.test.ts @@ -16,17 +16,18 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3358', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Ternary operators should not be nested', rule, { - valid: [ - { - code: `var a = condition ? 1 : 2; // OK`, - }, - { - code: ` + it('S3358', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Ternary operators should not be nested', rule, { + valid: [ + { + code: `var a = condition ? 1 : 2; // OK`, + }, + { + code: ` var foo = condition ? bar : function() { @@ -35,31 +36,31 @@ describe('S3358', () => { } return g; }`, - }, - { - code: ` + }, + { + code: ` var a = condition ? 1 : (function() { return condition2 ? 1 : 2; // OK, nesting is broken by function expression })();`, - }, - { - code: ` + }, + { + code: ` var foo = condition ? bar : (x => condition2 ? 1 : 2); // OK, nesting is broken by arrow function`, - }, - { - code: ` + }, + { + code: ` var foo = condition ? bar : function* gen() { yield condition2 ? 1 : 2 // OK, nesting is broken by generator }`, - }, - { - code: ` + }, + { + code: ` var obj = condition ? { a: 1, @@ -69,15 +70,15 @@ describe('S3358', () => { a: 1, b: condition2 ? 1 : 2 // OK, nesting is broken by object literal }`, - }, - { - code: ` + }, + { + code: ` var arr = condition ? [1, 2] : [1, condition2 ? 1 : 2] // OK, nesting is broken by array literal`, - }, - { - code: ` + }, + { + code: ` function Component(isLoading, isEditing) { const [saving, setSaving] = useState(false); return ( @@ -94,54 +95,55 @@ describe('S3358', () => { ); } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` // nested on the true side var a = condition ? 1 : (condition2 ? 1 : 2);`, - errors: [ - { - message: 'Extract this nested ternary operation into an independent statement.', - line: 3, - column: 32, - endLine: 3, - endColumn: 50, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Extract this nested ternary operation into an independent statement.', + line: 3, + column: 32, + endLine: 3, + endColumn: 50, + }, + ], + }, + { + code: ` // nested on the false side var a = condition ? 1 : (condition2 ? 1 : 2);`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` // nested on both sides var a = condition ? (condition2 ? 1 : 2) : (condition3 ? 1 : 2);`, - errors: 2, - }, - { - code: ` + errors: 2, + }, + { + code: ` // nested and re-nested var a = condition ? 1 : (condition2 ? 1 : (condition3 ? 1 : 2));`, - errors: 2, - }, - { - code: ` + errors: 2, + }, + { + code: ` var a = condition ? 1 : foo("hello", condition2 ? 1 : 2);`, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3402/unit.test.ts b/packages/jsts/src/rules/S3402/unit.test.ts index c3dd8358d5..d3d7eca0c5 100644 --- a/packages/jsts/src/rules/S3402/unit.test.ts +++ b/packages/jsts/src/rules/S3402/unit.test.ts @@ -16,44 +16,45 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3402', () => { - const ruleTesterTs = new RuleTester(); - ruleTesterTs.run('', rule, { - valid: [ - { - code: `function literal_type(param) { + it('S3402', () => { + const ruleTesterTs = new RuleTester(); + ruleTesterTs.run('', rule, { + valid: [ + { + code: `function literal_type(param) { var str = '42'; (param ? 'a' : 'b') + str; }`, - }, - { - code: `function assignable_to_string(param, obj: object, maybeStr: string | Object) { + }, + { + code: `function assignable_to_string(param, obj: object, maybeStr: string | Object) { var str = '42'; str + param; str + obj; str + maybeStr; }`, - }, - { - code: ` + }, + { + code: ` var str = "42"; var num = 1; return "foo" + num + "bar" + num; `, - }, - { - code: `42 + 42`, - }, - { - code: `"a" + "b"`, - }, - { - code: `"a" + 42`, // excluding string literals - }, - { - code: ` + }, + { + code: `42 + 42`, + }, + { + code: `"a" + "b"`, + }, + { + code: `"a" + 42`, // excluding string literals + }, + { + code: ` var str = "42"; var num = 1; // cast string operand to number @@ -64,92 +65,92 @@ describe('S3402', () => { foo('' + num + str); // Compliant foo(num.toString() + str); // Compliant `, - }, - { - code: ` + }, + { + code: ` function bar1(str) { foo(1 + str); // FN } bar1("42");`, - }, - { - code: ` + }, + { + code: ` var str = "42"; var num = 1; num * str`, - }, - { - code: ` + }, + { + code: ` declare enum E { X, Y } const a = 1 + E.X; `, - }, - { - code: ` + }, + { + code: ` var str = "42"; var num = 1; num *= str; str *= num`, - }, - { - code: ` + }, + { + code: ` var str1 = "42"; var str2 = "24"; str1 += str2; `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` var str = "42"; var num = 1; num + str`, - errors: [ - { - message: JSON.stringify({ - message: `Review this expression to be sure that the concatenation was intended.`, - secondaryLocations: [ - { - message: `left operand has type number.`, - column: 6, - line: 4, - endColumn: 9, - endLine: 4, - }, - { - message: `right operand has type string.`, - column: 12, - line: 4, - endColumn: 15, - endLine: 4, - }, - ], - }), - line: 4, - endLine: 4, - column: 11, - endColumn: 12, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `Review this expression to be sure that the concatenation was intended.`, + secondaryLocations: [ + { + message: `left operand has type number.`, + column: 6, + line: 4, + endColumn: 9, + endLine: 4, + }, + { + message: `right operand has type string.`, + column: 12, + line: 4, + endColumn: 15, + endLine: 4, + }, + ], + }), + line: 4, + endLine: 4, + column: 11, + endColumn: 12, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` var str = "42"; var num = 1; str + num`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` var str = "42"; var num = 1; num * 5 + str`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` var str = "42"; var obj = { num : 1, @@ -158,19 +159,19 @@ describe('S3402', () => { foo(obj + str); // Noncompliant foo(obj.num + str); // Noncompliant foo(obj.str + str); // Compliant`, - errors: [ - { - message: 'Review this expression to be sure that the concatenation was intended.', - line: 7, - }, - { - message: 'Review this expression to be sure that the concatenation was intended.', - line: 8, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Review this expression to be sure that the concatenation was intended.', + line: 7, + }, + { + message: 'Review this expression to be sure that the concatenation was intended.', + line: 8, + }, + ], + }, + { + code: ` var str = "42"; var obj = { num: 1, @@ -179,17 +180,18 @@ describe('S3402', () => { str += obj; obj += str; `, - errors: [ - { - message: 'Review this expression to be sure that the concatenation was intended.', - line: 7, - }, - { - message: 'Review this expression to be sure that the concatenation was intended.', - line: 8, - }, - ], - }, - ], + errors: [ + { + message: 'Review this expression to be sure that the concatenation was intended.', + line: 7, + }, + { + message: 'Review this expression to be sure that the concatenation was intended.', + line: 8, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3403/unit.test.ts b/packages/jsts/src/rules/S3403/unit.test.ts index 831fc7961b..44ed330788 100644 --- a/packages/jsts/src/rules/S3403/unit.test.ts +++ b/packages/jsts/src/rules/S3403/unit.test.ts @@ -16,221 +16,224 @@ */ import { rule } from './index.js'; import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3403', () => { - const ruleTesterJs = new DefaultParserRuleTester(); - ruleTesterJs.run( - 'Strict equality operators should not be used with dissimilar types [js]', - rule, - { - valid: [ - { - code: `'str' === false; // not reported without type information`, - }, - ], - invalid: [], - }, - ); + it('S3403', () => { + const ruleTesterJs = new DefaultParserRuleTester(); + ruleTesterJs.run( + 'Strict equality operators should not be used with dissimilar types [js]', + rule, + { + valid: [ + { + code: `'str' === false; // not reported without type information`, + }, + ], + invalid: [], + }, + ); - const ruleTesterTs = new RuleTester(); - ruleTesterTs.run( - `Strict equality operators should not be used with dissimilar types [ts]`, - rule, - { - valid: [ - { - code: ` + const ruleTesterTs = new RuleTester(); + ruleTesterTs.run( + `Strict equality operators should not be used with dissimilar types [ts]`, + rule, + { + valid: [ + { + code: ` let str = 'str', num = 5; str == num;`, - }, - { - code: ` + }, + { + code: ` let str = 'str', num = 5; str != num;`, - }, - { - code: ` + }, + { + code: ` let n = 4, m = 5; n === m;`, - }, - { - code: ` + }, + { + code: ` let n = 4, m = 5; n !== m;`, - }, - { - code: ` + }, + { + code: ` let s = 'hello', t = 'world'; s === t;`, - }, - { - code: ` + }, + { + code: ` let s = 'hello', t = 'world'; s !== t;`, - }, - { - code: ` + }, + { + code: ` let b = true, v = false; b === v;`, - }, - { - code: ` + }, + { + code: ` let b = true, v = false; b !== v;`, - }, - { - code: ` + }, + { + code: ` let o = {}, p = { prop: 1 }; o === p;`, - }, - { - code: ` + }, + { + code: ` let o = {}, p = { prop: 1 }; o !== p;`, - }, - { - code: ` + }, + { + code: ` let whatever, anything; whatever === anything;`, - }, - { - code: ` + }, + { + code: ` let whatever, anything; whatever !== anything;`, - }, - { - code: ` + }, + { + code: ` let str = 'str'; str === any;`, - }, - { - code: ` + }, + { + code: ` let str = 'str'; str !== any;`, - }, - { - code: ` + }, + { + code: ` let str = 'str', nulll = null; str === nulll;`, - }, - { - code: ` + }, + { + code: ` let str = 'str', undefinedd = undefed; str !== undefinedd;`, - }, - { - code: ` + }, + { + code: ` let union: (string|boolean); let str: string; union === str;`, - }, - { - code: ` + }, + { + code: ` let union: (string|boolean); let str: string; str === union;`, - }, - { - code: ` + }, + { + code: ` class MyClass { m() { let that = new MyClass(); return this === that; } }`, - }, - { - code: ` + }, + { + code: ` let str = 'str', obj = {}; str === obj;`, - }, - { - code: ` + }, + { + code: ` let str = 'str', obj = {}; str !== obj;`, - }, - { - code: ` + }, + { + code: ` const foo = Symbol('foo'); const symbols = [ foo ]; symbols.filter(symbol => symbol !== foo); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` let str = 'str', num = 5; str === num;`, - errors: [ - { - message: JSON.stringify({ - message: `Remove this "===" check; it will always be false. Did you mean to use "=="?`, - secondaryLocations: [ + errors: [ + { + message: JSON.stringify({ + message: `Remove this "===" check; it will always be false. Did you mean to use "=="?`, + secondaryLocations: [ + { + column: 8, + line: 3, + endColumn: 11, + endLine: 3, + }, + { + column: 16, + line: 3, + endColumn: 19, + endLine: 3, + }, + ], + }), + line: 3, + column: 13, + endLine: 3, + endColumn: 16, + suggestions: [ { - column: 8, - line: 3, - endColumn: 11, - endLine: 3, - }, - { - column: 16, - line: 3, - endColumn: 19, - endLine: 3, - }, - ], - }), - line: 3, - column: 13, - endLine: 3, - endColumn: 16, - suggestions: [ - { - desc: 'Replace "===" with "=="', - output: ` + desc: 'Replace "===" with "=="', + output: ` let str = 'str', num = 5; str == num;`, - }, - ], - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + }, + ], + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` let str = 'str', num = 5; str !== num;`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` let str = 'str', bool = false; str === bool;`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` let str = 'str', bool = false; str !== bool;`, - errors: 1, - }, - { - code: `'foo' !== {};`, - errors: [ - { - message: 'Remove this "!==" check; it will always be true. Did you mean to use "!="?', - suggestions: [ - { - desc: 'Replace "!==" with "!="', - output: `'foo' != {};`, - }, - ], - }, - ], - }, - ], - }, - ); + errors: 1, + }, + { + code: `'foo' !== {};`, + errors: [ + { + message: + 'Remove this "!==" check; it will always be true. Did you mean to use "!="?', + suggestions: [ + { + desc: 'Replace "!==" with "!="', + output: `'foo' != {};`, + }, + ], + }, + ], + }, + ], + }, + ); + }); }); diff --git a/packages/jsts/src/rules/S3498/unit.test.ts b/packages/jsts/src/rules/S3498/unit.test.ts index 10882ed4f2..6dfb87d840 100644 --- a/packages/jsts/src/rules/S3498/unit.test.ts +++ b/packages/jsts/src/rules/S3498/unit.test.ts @@ -16,43 +16,45 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3498', () => { - const ruleTester = new RuleTester(); + it('S3498', () => { + const ruleTester = new RuleTester(); - ruleTester.run(`Object literal shorthand syntax should be used`, rule, { - valid: [ - { - code: `const obj = { foo };`, - }, - { - code: ` + ruleTester.run(`Object literal shorthand syntax should be used`, rule, { + valid: [ + { + code: `const obj = { foo };`, + }, + { + code: ` ({ foo: function(component, event, helper) {} }); `, - }, - ], - invalid: [ - { - code: `const obj = { foo: foo };`, - output: `const obj = { foo };`, - errors: [ - { - messageId: 'expectedPropertyShorthand', - line: 1, - column: 15, - endLine: 1, - endColumn: 18, - }, - ], - }, - { - code: `({ foo: foo });`, - output: `({ foo });`, - errors: 1, - }, - ], + }, + ], + invalid: [ + { + code: `const obj = { foo: foo };`, + output: `const obj = { foo };`, + errors: [ + { + messageId: 'expectedPropertyShorthand', + line: 1, + column: 15, + endLine: 1, + endColumn: 18, + }, + ], + }, + { + code: `({ foo: foo });`, + output: `({ foo });`, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3499/unit.test.ts b/packages/jsts/src/rules/S3499/unit.test.ts index dbee6b51b7..2a525301a1 100644 --- a/packages/jsts/src/rules/S3499/unit.test.ts +++ b/packages/jsts/src/rules/S3499/unit.test.ts @@ -16,17 +16,18 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3499', () => { - const ruleTester = new RuleTester(); - ruleTester.run( - 'Shorthand object properties should be grouped at the beginning or end of an object declaration', - rule, - { - valid: [ - { - code: ` + it('S3499', () => { + const ruleTester = new RuleTester(); + ruleTester.run( + 'Shorthand object properties should be grouped at the beginning or end of an object declaration', + rule, + { + valid: [ + { + code: ` let obj2 = { foo, color, @@ -58,30 +59,30 @@ describe('S3499', () => { prop2, prop3 : value3 }`, - }, - ], - invalid: [ - { - code: `let obj1 = { // Main location + }, + ], + invalid: [ + { + code: `let obj1 = { // Main location foo, // Secondary location a: 1, color, // Secondary location b: 2, judyGarland // Secondary location }`, - errors: [ - { - message: `{\"message\":\"Group all shorthand properties at either the beginning or end of this object declaration.\",\"secondaryLocations\":[{\"message\":\"Move to either the beginning or end\",\"column\":12,\"line\":2,\"endColumn\":15,\"endLine\":2},{\"message\":\"Move to either the beginning or end\",\"column\":12,\"line\":4,\"endColumn\":17,\"endLine\":4},{\"message\":\"Move to either the beginning or end\",\"column\":12,\"line\":6,\"endColumn\":23,\"endLine\":6}]}`, - line: 1, - endLine: 1, - column: 12, - endColumn: 13, - }, - ], - options: ['sonar-runtime'], - }, - { - code: `let obj1 = { // Main location + errors: [ + { + message: `{\"message\":\"Group all shorthand properties at either the beginning or end of this object declaration.\",\"secondaryLocations\":[{\"message\":\"Move to either the beginning or end\",\"column\":12,\"line\":2,\"endColumn\":15,\"endLine\":2},{\"message\":\"Move to either the beginning or end\",\"column\":12,\"line\":4,\"endColumn\":17,\"endLine\":4},{\"message\":\"Move to either the beginning or end\",\"column\":12,\"line\":6,\"endColumn\":23,\"endLine\":6}]}`, + line: 1, + endLine: 1, + column: 12, + endColumn: 13, + }, + ], + options: ['sonar-runtime'], + }, + { + code: `let obj1 = { // Main location foo, color, a: 1, @@ -89,19 +90,19 @@ describe('S3499', () => { b: 2, judyGarland // Secondary location }`, - errors: [ - { - message: `{\"message\":\"Group all shorthand properties at the beginning of this object declaration.\",\"secondaryLocations\":[{\"message\":\"Move to the beginning\",\"column\":20,\"line\":5,\"endColumn\":21,\"endLine\":5},{\"message\":\"Move to the beginning\",\"column\":20,\"line\":7,\"endColumn\":31,\"endLine\":7}]}`, - line: 1, - endLine: 1, - column: 12, - endColumn: 13, - }, - ], - options: ['sonar-runtime'], - }, - { - code: `let obj6 = { // Main location + errors: [ + { + message: `{\"message\":\"Group all shorthand properties at the beginning of this object declaration.\",\"secondaryLocations\":[{\"message\":\"Move to the beginning\",\"column\":20,\"line\":5,\"endColumn\":21,\"endLine\":5},{\"message\":\"Move to the beginning\",\"column\":20,\"line\":7,\"endColumn\":31,\"endLine\":7}]}`, + line: 1, + endLine: 1, + column: 12, + endColumn: 13, + }, + ], + options: ['sonar-runtime'], + }, + { + code: `let obj6 = { // Main location a: 1, foo, // Secondary location color, // Secondary location @@ -109,18 +110,19 @@ describe('S3499', () => { c, judyGarland }`, - errors: [ - { - message: `{"message":"Group all shorthand properties at the end of this object declaration.","secondaryLocations":[{"message":"Move to the end","column":20,"line":3,"endColumn":23,"endLine":3},{"message":"Move to the end","column":20,"line":4,"endColumn":25,"endLine":4}]}`, - line: 1, - endLine: 1, - column: 12, - endColumn: 13, - }, - ], - options: ['sonar-runtime'], - }, - ], - }, - ); + errors: [ + { + message: `{"message":"Group all shorthand properties at the end of this object declaration.","secondaryLocations":[{"message":"Move to the end","column":20,"line":3,"endColumn":23,"endLine":3},{"message":"Move to the end","column":20,"line":4,"endColumn":25,"endLine":4}]}`, + line: 1, + endLine: 1, + column: 12, + endColumn: 13, + }, + ], + options: ['sonar-runtime'], + }, + ], + }, + ); + }); }); diff --git a/packages/jsts/src/rules/S3500/unit.test.ts b/packages/jsts/src/rules/S3500/unit.test.ts index b94e2f13c3..19f3604f55 100644 --- a/packages/jsts/src/rules/S3500/unit.test.ts +++ b/packages/jsts/src/rules/S3500/unit.test.ts @@ -16,35 +16,37 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3500', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Attempts should not be made to update "const" variables', rule, { - valid: [], - invalid: [ - { - code: ` + it('S3500', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Attempts should not be made to update "const" variables', rule, { + valid: [], + invalid: [ + { + code: ` const c = 1; c = 2;`, - errors: [ - { - message: - '{"message":"Correct this attempt to modify \\"c\\" or use \\"let\\" in its declaration.","secondaryLocations":[{"message":"Const declaration","column":8,"line":2,"endColumn":20,"endLine":2}]}', - line: 3, - column: 9, - endLine: 3, - endColumn: 10, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: + '{"message":"Correct this attempt to modify \\"c\\" or use \\"let\\" in its declaration.","secondaryLocations":[{"message":"Const declaration","column":8,"line":2,"endColumn":20,"endLine":2}]}', + line: 3, + column: 9, + endLine: 3, + endColumn: 10, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const c = 1; var x = c++;`, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3512/unit.test.ts b/packages/jsts/src/rules/S3512/unit.test.ts index 9db86edad4..e0c8b094de 100644 --- a/packages/jsts/src/rules/S3512/unit.test.ts +++ b/packages/jsts/src/rules/S3512/unit.test.ts @@ -16,52 +16,54 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3512', () => { - const ruleTester = new RuleTester(); + it('S3512', () => { + const ruleTester = new RuleTester(); - ruleTester.run(`Template strings should be used instead of concatenation`, rule, { - valid: [ - { - code: `'hello' + 5;`, - }, - { - code: `5 + 'hello'`, - }, - { - code: `'hello' + 'world';`, - }, - ], - invalid: [ - { - code: `5 + 'hello' + 10;`, - errors: [ - { - message: `Unexpected string concatenation.`, - line: 1, - endLine: 1, - column: 1, - endColumn: 17, - }, - ], - output: '`${5 }hello${ 10}`;', - }, - { - code: `'hello' + 5 + 'world';`, - output: '`hello${ 5 }world`;', - errors: 1, - }, - { - code: `'hello' + 'world' + 5;`, - output: '`hello` + `world${ 5}`;', - errors: 1, - }, - { - code: `5 + 'hello' + 'world';`, - output: '`${5 }hello` + `world`;', - errors: 1, - }, - ], + ruleTester.run(`Template strings should be used instead of concatenation`, rule, { + valid: [ + { + code: `'hello' + 5;`, + }, + { + code: `5 + 'hello'`, + }, + { + code: `'hello' + 'world';`, + }, + ], + invalid: [ + { + code: `5 + 'hello' + 10;`, + errors: [ + { + message: `Unexpected string concatenation.`, + line: 1, + endLine: 1, + column: 1, + endColumn: 17, + }, + ], + output: '`${5 }hello${ 10}`;', + }, + { + code: `'hello' + 5 + 'world';`, + output: '`hello${ 5 }world`;', + errors: 1, + }, + { + code: `'hello' + 'world' + 5;`, + output: '`hello` + `world${ 5}`;', + errors: 1, + }, + { + code: `5 + 'hello' + 'world';`, + output: '`${5 }hello` + `world`;', + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3513/unit.test.ts b/packages/jsts/src/rules/S3513/unit.test.ts index 90a012b737..044b15544d 100644 --- a/packages/jsts/src/rules/S3513/unit.test.ts +++ b/packages/jsts/src/rules/S3513/unit.test.ts @@ -16,15 +16,16 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3513', () => { - const ruleTester = new RuleTester(); + it('S3513', () => { + const ruleTester = new RuleTester(); - ruleTester.run(`"arguments" should not be accessed directly`, rule, { - valid: [ - { - code: ` + ruleTester.run(`"arguments" should not be accessed directly`, rule, { + valid: [ + { + code: ` function foo_ok1(a, b) { return a + b; } @@ -51,11 +52,11 @@ function foo_ok5(a) { var arguments = 1; // OK, global foo(arguments); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function foo1() { foo(arguments); // Noncompliant } @@ -65,38 +66,39 @@ const foo2 = function() { foo(arguments[1]); } `, - options: ['sonar-runtime'], - errors: [ - { - message: JSON.stringify({ - message: "Use the rest syntax to declare this function's arguments.", - secondaryLocations: [], - }), - line: 3, - endLine: 3, - column: 7, - endColumn: 16, - }, - { - message: JSON.stringify({ - message: "Use the rest syntax to declare this function's arguments.", - secondaryLocations: [ - { - message: 'Replace this reference to "arguments".', - column: 6, - line: 8, - endColumn: 15, - endLine: 8, - }, - ], - }), - line: 7, - endLine: 7, - column: 7, - endColumn: 16, - }, - ], - }, - ], + options: ['sonar-runtime'], + errors: [ + { + message: JSON.stringify({ + message: "Use the rest syntax to declare this function's arguments.", + secondaryLocations: [], + }), + line: 3, + endLine: 3, + column: 7, + endColumn: 16, + }, + { + message: JSON.stringify({ + message: "Use the rest syntax to declare this function's arguments.", + secondaryLocations: [ + { + message: 'Replace this reference to "arguments".', + column: 6, + line: 8, + endColumn: 15, + endLine: 8, + }, + ], + }), + line: 7, + endLine: 7, + column: 7, + endColumn: 16, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3514/unit.test.ts b/packages/jsts/src/rules/S3514/unit.test.ts index e75947cd97..4871494570 100644 --- a/packages/jsts/src/rules/S3514/unit.test.ts +++ b/packages/jsts/src/rules/S3514/unit.test.ts @@ -16,14 +16,15 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3514', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Destructuring syntax should be used for assignments', rule, { - valid: [ - { - code: `function foo(obj1, obj2, arr1, arr2) { + it('S3514', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Destructuring syntax should be used for assignments', rule, { + valid: [ + { + code: `function foo(obj1, obj2, arr1, arr2) { var e = obj1.e; // OK, different objects var d = obj2.d; foo(); @@ -66,11 +67,11 @@ describe('S3514', () => { t = obj1.t; // OK, destructuring can appear in declaration only r = obj1.r; }`, - }, - ], - invalid: [ - { - code: `function foo(obj1, obj2) { + }, + ], + invalid: [ + { + code: `function foo(obj1, obj2) { var c = obj1.c; // Noncompliant var d = obj1.d; // Secondary location @@ -87,37 +88,37 @@ describe('S3514', () => { var x = obj1.prop.x, y = obj1.prop.y; // Noncompliant }`, - errors: [ - { - message: `{\"message\":\"Use destructuring syntax for these assignments from \\\"obj1\\\".\",\"secondaryLocations\":[{\"message\":\"Replace this assignment.\",\"column\":16,\"line\":3,\"endColumn\":26,\"endLine\":3}]}`, - line: 2, - endLine: 2, - column: 17, - endColumn: 27, - }, - { - message: `{\"message\":\"Use destructuring syntax for these assignments from \\\"obj2\\\".\",\"secondaryLocations\":[{\"message\":\"Replace this assignment.\",\"column\":28,\"line\":7,\"endColumn\":38,\"endLine\":7}]}`, - line: 7, - endLine: 7, - column: 17, - endColumn: 27, - }, - { - message: `{\"message\":\"Use destructuring syntax for these assignments from \\\"obj1\\\".\",\"secondaryLocations\":[{\"message\":\"Replace this assignment.\",\"column\":16,\"line\":12,\"endColumn\":26,\"endLine\":12},{\"message\":\"Replace this assignment.\",\"column\":28,\"line\":12,\"endColumn\":38,\"endLine\":12}]}`, - line: 11, - endLine: 11, - column: 17, - endColumn: 27, - }, - { - message: `{\"message\":\"Use destructuring syntax for these assignments from \\\"obj1.prop\\\".\",\"secondaryLocations\":[{\"message\":\"Replace this assignment.\",\"column\":33,\"line\":16,\"endColumn\":48,\"endLine\":16}]}`, - line: 16, - }, - ], - options: ['sonar-runtime'], - }, - { - code: `function foo(arr1, arr2) { + errors: [ + { + message: `{\"message\":\"Use destructuring syntax for these assignments from \\\"obj1\\\".\",\"secondaryLocations\":[{\"message\":\"Replace this assignment.\",\"column\":16,\"line\":3,\"endColumn\":26,\"endLine\":3}]}`, + line: 2, + endLine: 2, + column: 17, + endColumn: 27, + }, + { + message: `{\"message\":\"Use destructuring syntax for these assignments from \\\"obj2\\\".\",\"secondaryLocations\":[{\"message\":\"Replace this assignment.\",\"column\":28,\"line\":7,\"endColumn\":38,\"endLine\":7}]}`, + line: 7, + endLine: 7, + column: 17, + endColumn: 27, + }, + { + message: `{\"message\":\"Use destructuring syntax for these assignments from \\\"obj1\\\".\",\"secondaryLocations\":[{\"message\":\"Replace this assignment.\",\"column\":16,\"line\":12,\"endColumn\":26,\"endLine\":12},{\"message\":\"Replace this assignment.\",\"column\":28,\"line\":12,\"endColumn\":38,\"endLine\":12}]}`, + line: 11, + endLine: 11, + column: 17, + endColumn: 27, + }, + { + message: `{\"message\":\"Use destructuring syntax for these assignments from \\\"obj1.prop\\\".\",\"secondaryLocations\":[{\"message\":\"Replace this assignment.\",\"column\":33,\"line\":16,\"endColumn\":48,\"endLine\":16}]}`, + line: 16, + }, + ], + options: ['sonar-runtime'], + }, + { + code: `function foo(arr1, arr2) { const one1 = arr1[0]; // Noncompliant const two1 = arr1[1]; const three1 = arr1[2]; @@ -126,20 +127,20 @@ describe('S3514', () => { let one = arr1[0], two = arr1[1]; // Noncompliant }`, - errors: [ - { - message: `{\"message\":\"Use destructuring syntax for these assignments from \\\"arr1\\\".\",\"secondaryLocations\":[{\"message\":\"Replace this assignment.\",\"column\":22,\"line\":3,\"endColumn\":36,\"endLine\":3},{\"message\":\"Replace this assignment.\",\"column\":22,\"line\":4,\"endColumn\":38,\"endLine\":4}]}`, - line: 2, - }, - { - messageId: 'sonarRuntime', - line: 8, - }, - ], - options: ['sonar-runtime'], - }, - { - code: `// switch cases + errors: [ + { + message: `{\"message\":\"Use destructuring syntax for these assignments from \\\"arr1\\\".\",\"secondaryLocations\":[{\"message\":\"Replace this assignment.\",\"column\":22,\"line\":3,\"endColumn\":36,\"endLine\":3},{\"message\":\"Replace this assignment.\",\"column\":22,\"line\":4,\"endColumn\":38,\"endLine\":4}]}`, + line: 2, + }, + { + messageId: 'sonarRuntime', + line: 8, + }, + ], + options: ['sonar-runtime'], + }, + { + code: `// switch cases switch (a) { case 1: var x = obj.x; // Noncompliant @@ -148,28 +149,29 @@ describe('S3514', () => { default: var c = obj.c, d = obj.d; // Noncompliant }`, - errors: [ - { - message: 'Use destructuring syntax for these assignments from "obj".', - line: 4, - }, - { - message: 'Use destructuring syntax for these assignments from "obj".', - line: 8, - }, - ], - }, - { - code: `// global scope + errors: [ + { + message: 'Use destructuring syntax for these assignments from "obj".', + line: 4, + }, + { + message: 'Use destructuring syntax for these assignments from "obj".', + line: 8, + }, + ], + }, + { + code: `// global scope var obj = foo(); var a = obj.a, b = obj.b; // Noncompliant`, - errors: [ - { - message: 'Use destructuring syntax for these assignments from "obj".', - line: 3, - }, - ], - }, - ], + errors: [ + { + message: 'Use destructuring syntax for these assignments from "obj".', + line: 3, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3516/unit.test.ts b/packages/jsts/src/rules/S3516/unit.test.ts index 0687c56a41..88273ba7ac 100644 --- a/packages/jsts/src/rules/S3516/unit.test.ts +++ b/packages/jsts/src/rules/S3516/unit.test.ts @@ -16,15 +16,16 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3516', () => { - const ruleTester = new RuleTester(); + it('S3516', () => { + const ruleTester = new RuleTester(); - ruleTester.run(`Function returns should not be invariant`, rule, { - valid: [ - { - code: ` + ruleTester.run(`Function returns should not be invariant`, rule, { + valid: [ + { + code: ` function identifiers1(a: number) { const c = "foo"; if (a == 1) { @@ -116,9 +117,9 @@ describe('S3516', () => { doSomething(c); // Ok - we don't know whether state of c was updated or not return c; }`, - }, - { - code: ` + }, + { + code: ` function oneReturnValue() { return 1; } @@ -214,37 +215,37 @@ describe('S3516', () => { return num2; } }`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function numbers(a: number) { if (a == 1) { return 42; } return 42; }`, - errors: [ - { - message: JSON.stringify({ - message: 'Refactor this function to not always return the same value.', - secondaryLocations: [ - { message: 'Returned value.', column: 21, line: 4, endColumn: 23, endLine: 4 }, - { message: 'Returned value.', column: 17, line: 6, endColumn: 19, endLine: 6 }, - ], - cost: 2, - }), - line: 2, - endLine: 2, - column: 18, - endColumn: 25, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: 'Refactor this function to not always return the same value.', + secondaryLocations: [ + { message: 'Returned value.', column: 21, line: 4, endColumn: 23, endLine: 4 }, + { message: 'Returned value.', column: 17, line: 6, endColumn: 19, endLine: 6 }, + ], + cost: 2, + }), + line: 2, + endLine: 2, + column: 18, + endColumn: 25, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` function strings(a: number) { if (a == 1) { return "foo"; @@ -253,43 +254,43 @@ describe('S3516', () => { } return "foo"; }`, - errors: [ - { - message: JSON.stringify({ - message: 'Refactor this function to not always return the same value.', - secondaryLocations: [ - { message: 'Returned value.', column: 21, line: 4, endColumn: 26, endLine: 4 }, - { message: 'Returned value.', column: 21, line: 6, endColumn: 26, endLine: 6 }, - { message: 'Returned value.', column: 19, line: 8, endColumn: 24, endLine: 8 }, - ], - cost: 3, - }), - line: 2, - endLine: 2, - }, - ], - options: ['sonar-runtime'], - }, - { - code: `var arrowNok = (p) => { if (p) { return "foo"; } return "foo"; };`, - errors: [ - { - message: JSON.stringify({ - message: 'Refactor this function to not always return the same value.', - secondaryLocations: [ - { message: 'Returned value.', column: 40, line: 1, endColumn: 45, endLine: 1 }, - { message: 'Returned value.', column: 56, line: 1, endColumn: 61, endLine: 1 }, - ], - cost: 2, - }), - line: 1, - endLine: 1, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: 'Refactor this function to not always return the same value.', + secondaryLocations: [ + { message: 'Returned value.', column: 21, line: 4, endColumn: 26, endLine: 4 }, + { message: 'Returned value.', column: 21, line: 6, endColumn: 26, endLine: 6 }, + { message: 'Returned value.', column: 19, line: 8, endColumn: 24, endLine: 8 }, + ], + cost: 3, + }), + line: 2, + endLine: 2, + }, + ], + options: ['sonar-runtime'], + }, + { + code: `var arrowNok = (p) => { if (p) { return "foo"; } return "foo"; };`, + errors: [ + { + message: JSON.stringify({ + message: 'Refactor this function to not always return the same value.', + secondaryLocations: [ + { message: 'Returned value.', column: 40, line: 1, endColumn: 45, endLine: 1 }, + { message: 'Returned value.', column: 56, line: 1, endColumn: 61, endLine: 1 }, + ], + cost: 2, + }), + line: 1, + endLine: 1, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` function identifiers(a: number) { const c = "foo"; if (a == 1) { @@ -297,24 +298,24 @@ describe('S3516', () => { } return c; }`, - errors: [ - { - message: JSON.stringify({ - message: 'Refactor this function to not always return the same value.', - secondaryLocations: [ - { message: 'Returned value.', column: 21, line: 5, endColumn: 22, endLine: 5 }, - { message: 'Returned value.', column: 17, line: 7, endColumn: 18, endLine: 7 }, - ], - cost: 2, - }), - line: 2, - endLine: 2, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: 'Refactor this function to not always return the same value.', + secondaryLocations: [ + { message: 'Returned value.', column: 21, line: 5, endColumn: 22, endLine: 5 }, + { message: 'Returned value.', column: 17, line: 7, endColumn: 18, endLine: 7 }, + ], + cost: 2, + }), + line: 2, + endLine: 2, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` function identifiers(count) { count -= 1; if (count <= 0) { @@ -324,24 +325,24 @@ describe('S3516', () => { const var2 = doSomethingElse(); return count; }`, - errors: [ - { - message: JSON.stringify({ - message: 'Refactor this function to not always return the same value.', - secondaryLocations: [ - { message: 'Returned value.', column: 19, line: 5, endColumn: 24, endLine: 5 }, - { message: 'Returned value.', column: 17, line: 9, endColumn: 22, endLine: 9 }, - ], - cost: 2, - }), - line: 2, - endLine: 2, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: 'Refactor this function to not always return the same value.', + secondaryLocations: [ + { message: 'Returned value.', column: 19, line: 5, endColumn: 24, endLine: 5 }, + { message: 'Returned value.', column: 17, line: 9, endColumn: 22, endLine: 9 }, + ], + cost: 2, + }), + line: 2, + endLine: 2, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` function numbers(a: number) { if (a == 1) { return 42; @@ -349,24 +350,24 @@ describe('S3516', () => { var arrowNull = (p) => { if (p) { return null; } return ""; }; return 42; }`, - errors: [ - { - message: JSON.stringify({ - message: 'Refactor this function to not always return the same value.', - secondaryLocations: [ - { message: 'Returned value.', column: 21, line: 4, endColumn: 23, endLine: 4 }, - { message: 'Returned value.', column: 17, line: 7, endColumn: 19, endLine: 7 }, - ], - cost: 2, - }), - line: 2, - endLine: 2, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: 'Refactor this function to not always return the same value.', + secondaryLocations: [ + { message: 'Returned value.', column: 21, line: 4, endColumn: 23, endLine: 4 }, + { message: 'Returned value.', column: 17, line: 7, endColumn: 19, endLine: 7 }, + ], + cost: 2, + }), + line: 2, + endLine: 2, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` function numbers(a: number) { if (a == 1) { return 42; @@ -374,24 +375,24 @@ describe('S3516', () => { var arrowNull = (p) => { if (p) { return ""; } return ""; }; return ""; }`, - errors: [ - { - message: JSON.stringify({ - message: 'Refactor this function to not always return the same value.', - secondaryLocations: [ - { message: 'Returned value.', column: 51, line: 6, endColumn: 53, endLine: 6 }, - { message: 'Returned value.', column: 64, line: 6, endColumn: 66, endLine: 6 }, - ], - cost: 2, - }), - line: 6, - endLine: 6, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: 'Refactor this function to not always return the same value.', + secondaryLocations: [ + { message: 'Returned value.', column: 51, line: 6, endColumn: 53, endLine: 6 }, + { message: 'Returned value.', column: 64, line: 6, endColumn: 66, endLine: 6 }, + ], + cost: 2, + }), + line: 6, + endLine: 6, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` function identifiers(a: number) { let c; c = 1; @@ -400,22 +401,22 @@ describe('S3516', () => { } return c; }`, - errors: [ - { - message: JSON.stringify({ - message: 'Refactor this function to not always return the same value.', - secondaryLocations: [ - { message: 'Returned value.', column: 21, line: 6, endColumn: 22, endLine: 6 }, - { message: 'Returned value.', column: 17, line: 8, endColumn: 18, endLine: 8 }, - ], - cost: 2, - }), - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: 'Refactor this function to not always return the same value.', + secondaryLocations: [ + { message: 'Returned value.', column: 21, line: 6, endColumn: 22, endLine: 6 }, + { message: 'Returned value.', column: 17, line: 8, endColumn: 18, endLine: 8 }, + ], + cost: 2, + }), + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` function withThrowAndExplicitReturn(cond: boolean, cond2: boolean) { try { throw 42; @@ -426,22 +427,22 @@ describe('S3516', () => { } return 42; }`, - errors: [ - { - message: JSON.stringify({ - message: 'Refactor this function to not always return the same value.', - secondaryLocations: [ - { message: 'Returned value.', column: 21, line: 8, endColumn: 23, endLine: 8 }, - { message: 'Returned value.', column: 17, line: 10, endColumn: 19, endLine: 10 }, - ], - cost: 2, - }), - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: 'Refactor this function to not always return the same value.', + secondaryLocations: [ + { message: 'Returned value.', column: 21, line: 8, endColumn: 23, endLine: 8 }, + { message: 'Returned value.', column: 17, line: 10, endColumn: 19, endLine: 10 }, + ], + cost: 2, + }), + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` registerFunction( function() { const c = "foo"; @@ -450,24 +451,24 @@ describe('S3516', () => { } return c; });`, - errors: [ - { - message: JSON.stringify({ - message: 'Refactor this function to not always return the same value.', - secondaryLocations: [ - { message: 'Returned value.', column: 23, line: 6, endColumn: 24, endLine: 6 }, - { message: 'Returned value.', column: 19, line: 8, endColumn: 20, endLine: 8 }, - ], - cost: 2, - }), - line: 3, - endLine: 3, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: 'Refactor this function to not always return the same value.', + secondaryLocations: [ + { message: 'Returned value.', column: 23, line: 6, endColumn: 24, endLine: 6 }, + { message: 'Returned value.', column: 19, line: 8, endColumn: 20, endLine: 8 }, + ], + cost: 2, + }), + line: 3, + endLine: 3, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` var arrowNull = (p) => { if (p) { return null; } return null; }; var arrowBoolean = (p) => { if (p) { return true; } return true; }; var arrowEquivalent1 = (p) => { if (p) { return !true; } return false; }; @@ -476,8 +477,9 @@ describe('S3516', () => { var arrowEquivalent4 = (p) => { if (p) { return !1; } return false; }; var arrowEquivalent5 = (p) => { if (p) { return "boolean"; } return typeof false; }; var arrowEquivalent6 = (p) => { if (p) { return ~4; } return -5; };`, - errors: 8, - }, - ], + errors: 8, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3524/unit.test.ts b/packages/jsts/src/rules/S3524/unit.test.ts index 4ae8774880..4d56b6ef4b 100644 --- a/packages/jsts/src/rules/S3524/unit.test.ts +++ b/packages/jsts/src/rules/S3524/unit.test.ts @@ -16,16 +16,20 @@ */ import { rule } from './index.js'; import { NoTypeCheckingRuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3524', () => { - const ruleTester = new NoTypeCheckingRuleTester(); + it('S3524', () => { + const ruleTester = new NoTypeCheckingRuleTester(); - ruleTester.run('Braces and parentheses should be used consistently with arrow functions', rule, { - valid: [ + ruleTester.run( + 'Braces and parentheses should be used consistently with arrow functions', + rule, { - filename: 'file.ts', - code: `// valid mandatory parentheses + valid: [ + { + filename: 'file.ts', + code: `// valid mandatory parentheses var foo = (a) => { foo(); } var foo = (a /*some comment*/) => { foo(); } var foo = (a, b) => { foo(); } @@ -45,11 +49,11 @@ var foo = async /**/ (y) => y var foo = async (/**/ y) => y var foo = async (y /**/) => y `, - options: [{ requireParameterParentheses: true, requireBodyBraces: false }], - }, - { - filename: 'file.ts', - code: `// valid optional parentheses + options: [{ requireParameterParentheses: true, requireBodyBraces: false }], + }, + { + filename: 'file.ts', + code: `// valid optional parentheses var foo = a => { foo(); } var foo = (a /*some comment*/) => { foo(); } var foo = (a :string) => { foo(); } @@ -80,10 +84,10 @@ foo = (x) => { return x; } foo = async (x) => { return x; } foo = async (x, y) => { return x; } `, - options: [{ requireParameterParentheses: false, requireBodyBraces: true }], - }, - { - code: `// valid mandatory braces + options: [{ requireParameterParentheses: false, requireBodyBraces: true }], + }, + { + code: `// valid mandatory braces var foo = (a, b) => { return a; } var foo = (a, b) => { foo(); } var foo = (a, b) => { return; } @@ -95,10 +99,10 @@ var foo = (a, b) => { .Bar(); } `, - options: [{ requireParameterParentheses: true, requireBodyBraces: true }], - }, - { - code: `// valid optional braces + options: [{ requireParameterParentheses: true, requireBodyBraces: true }], + }, + { + code: `// valid optional braces var foo = (a, b) => a; var foo = (a, b) => a + b; var foo = (a, b) => foo(a, b); @@ -112,106 +116,108 @@ var foo = (a, b) => { // OK, ignore multiline return .Bar(); } `, - options: [{ requireParameterParentheses: true, requireBodyBraces: false }], - }, - { - code: `x => x // parameter as the very first token`, - options: [{ requireParameterParentheses: false, requireBodyBraces: false }], - }, - ], - invalid: [ - { - code: `// invalid mandatory parentheses + options: [{ requireParameterParentheses: true, requireBodyBraces: false }], + }, + { + code: `x => x // parameter as the very first token`, + options: [{ requireParameterParentheses: false, requireBodyBraces: false }], + }, + ], + invalid: [ + { + code: `// invalid mandatory parentheses var foo = a => { foo(); } // Noncompliant var foo = async x => x `, - options: [{ requireParameterParentheses: true, requireBodyBraces: false }], - errors: [ - { - message: 'Add parentheses around the parameter of this arrow function.', - line: 2, - endLine: 2, - column: 11, - endColumn: 12, + options: [{ requireParameterParentheses: true, requireBodyBraces: false }], + errors: [ + { + message: 'Add parentheses around the parameter of this arrow function.', + line: 2, + endLine: 2, + column: 11, + endColumn: 12, + }, + { + message: 'Add parentheses around the parameter of this arrow function.', + line: 3, + endLine: 3, + column: 17, + endColumn: 18, + }, + ], }, { - message: 'Add parentheses around the parameter of this arrow function.', - line: 3, - endLine: 3, - column: 17, - endColumn: 18, - }, - ], - }, - { - code: `// invalid optional parentheses + code: `// invalid optional parentheses var foo = (a) => { foo(); /* comment */ } // Noncompliant var foo = async (x) => x `, - options: [{ requireParameterParentheses: false, requireBodyBraces: false }], - errors: [ - { - message: 'Remove parentheses around the parameter of this arrow function.', - line: 2, - endLine: 2, - column: 12, - endColumn: 13, + options: [{ requireParameterParentheses: false, requireBodyBraces: false }], + errors: [ + { + message: 'Remove parentheses around the parameter of this arrow function.', + line: 2, + endLine: 2, + column: 12, + endColumn: 13, + }, + { + message: 'Remove parentheses around the parameter of this arrow function.', + line: 3, + endLine: 3, + column: 18, + endColumn: 19, + }, + ], }, { - message: 'Remove parentheses around the parameter of this arrow function.', - line: 3, - endLine: 3, - column: 18, - endColumn: 19, - }, - ], - }, - { - code: `// invalid mandatory braces + code: `// invalid mandatory braces var foo = (a, b) => a + b; // Noncompliant var foo = (a, b) => foo(a, b); // Noncompliant var foo = (a, b) => a; // Noncompliant `, - options: [{ requireParameterParentheses: true, requireBodyBraces: true }], - errors: [ - { - message: 'Add curly braces and "return" to this arrow function body.', - line: 2, - endLine: 2, - column: 21, - endColumn: 26, - }, - { - message: 'Add curly braces and "return" to this arrow function body.', - line: 3, - endLine: 3, - column: 21, - endColumn: 30, + options: [{ requireParameterParentheses: true, requireBodyBraces: true }], + errors: [ + { + message: 'Add curly braces and "return" to this arrow function body.', + line: 2, + endLine: 2, + column: 21, + endColumn: 26, + }, + { + message: 'Add curly braces and "return" to this arrow function body.', + line: 3, + endLine: 3, + column: 21, + endColumn: 30, + }, + { + message: 'Add curly braces and "return" to this arrow function body.', + line: 4, + endLine: 4, + column: 21, + endColumn: 22, + }, + ], }, { - message: 'Add curly braces and "return" to this arrow function body.', - line: 4, - endLine: 4, - column: 21, - endColumn: 22, - }, - ], - }, - { - code: `// invalid optional braces + code: `// invalid optional braces var foo = (a, b) => { return a; } // Noncompliant `, - options: [{ requireParameterParentheses: true, requireBodyBraces: false }], - errors: [ - { - message: 'Remove curly braces and "return" from this arrow function body.', - line: 2, - endLine: 2, - column: 21, - endColumn: 34, + options: [{ requireParameterParentheses: true, requireBodyBraces: false }], + errors: [ + { + message: 'Remove curly braces and "return" from this arrow function body.', + line: 2, + endLine: 2, + column: 21, + endColumn: 34, + }, + ], }, ], }, - ], + ); }); }); diff --git a/packages/jsts/src/rules/S3525/unit.test.ts b/packages/jsts/src/rules/S3525/unit.test.ts index 8ff8e2b4f1..a5fe2d27f0 100644 --- a/packages/jsts/src/rules/S3525/unit.test.ts +++ b/packages/jsts/src/rules/S3525/unit.test.ts @@ -16,84 +16,86 @@ */ import { rule } from './index.js'; import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3525', () => { - const ruleTesterJs = new DefaultParserRuleTester(); - ruleTesterJs.run('Class methods should be used instead of "prototype" assignments [js]', rule, { - valid: [ - { - code: `Foo.prototype.property = 1;`, - }, - { - code: ` + it('S3525', () => { + const ruleTesterJs = new DefaultParserRuleTester(); + ruleTesterJs.run('Class methods should be used instead of "prototype" assignments [js]', rule, { + valid: [ + { + code: `Foo.prototype.property = 1;`, + }, + { + code: ` function Bar() {} Foo.prototype.property = Bar; // FN - we need type information`, - }, - { - code: `Foo.prototype = function () {};`, - }, - { - code: `Foo.proto.property = function () {};`, - }, - ], - invalid: [ - { - code: `Foo.prototype.property = function () {};`, - errors: [ - { - message: `Declare a \"Foo\" class and move this declaration of \"property\" into it.`, - line: 1, - endLine: 1, - column: 1, - endColumn: 23, - }, - ], - }, - { - code: ` + }, + { + code: `Foo.prototype = function () {};`, + }, + { + code: `Foo.proto.property = function () {};`, + }, + ], + invalid: [ + { + code: `Foo.prototype.property = function () {};`, + errors: [ + { + message: `Declare a \"Foo\" class and move this declaration of \"property\" into it.`, + line: 1, + endLine: 1, + column: 1, + endColumn: 23, + }, + ], + }, + { + code: ` const Bar = () => {}; Foo.prototype.property = () => {};`, - errors: 1, - }, - ], - }); + errors: 1, + }, + ], + }); - const ruleTesterTs = new RuleTester(); - ruleTesterTs.run('Class methods should be used instead of "prototype" assignments [ts]', rule, { - valid: [ - { - code: `Foo.prototype.property = 1;`, - }, - { - code: `Foo.prototype.property = Bar;`, - }, - ], - invalid: [ - { - code: `Foo.prototype.property = function () {};`, - errors: [ - { - message: `Declare a \"Foo\" class and move this declaration of \"property\" into it.`, - line: 1, - endLine: 1, - column: 1, - endColumn: 23, - }, - ], - }, - { - code: ` + const ruleTesterTs = new RuleTester(); + ruleTesterTs.run('Class methods should be used instead of "prototype" assignments [ts]', rule, { + valid: [ + { + code: `Foo.prototype.property = 1;`, + }, + { + code: `Foo.prototype.property = Bar;`, + }, + ], + invalid: [ + { + code: `Foo.prototype.property = function () {};`, + errors: [ + { + message: `Declare a \"Foo\" class and move this declaration of \"property\" into it.`, + line: 1, + endLine: 1, + column: 1, + endColumn: 23, + }, + ], + }, + { + code: ` function Bar() {} Foo.prototype.property = Bar;`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const Bar = () => {}; Foo.prototype.property = Bar;`, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3531/unit.test.ts b/packages/jsts/src/rules/S3531/unit.test.ts index 0ce491b3c4..dfe9b09dad 100644 --- a/packages/jsts/src/rules/S3531/unit.test.ts +++ b/packages/jsts/src/rules/S3531/unit.test.ts @@ -16,81 +16,82 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3531', () => { - const ruleTester = new RuleTester(); - const ruleTesterTs = new RuleTester(); + it('S3531', () => { + const ruleTester = new RuleTester(); + const ruleTesterTs = new RuleTester(); - const testCases = { - valid: [ - { - code: ` + const testCases = { + valid: [ + { + code: ` var foo = function * () { } `, - }, - { - code: ` + }, + { + code: ` var foo = function * () { let a = 3; yield a; } `, - }, - { - code: ` + }, + { + code: ` function someFunction() { doSomething(); } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function * foo() { // ^^^ return 1; } `, - errors: [ - { - message: `Add a "yield" statement to this generator.`, - line: 2, - endLine: 2, - column: 24, - endColumn: 27, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Add a "yield" statement to this generator.`, + line: 2, + endLine: 2, + column: 24, + endColumn: 27, + }, + ], + }, + { + code: ` var foo = function * () { // ^^^^^^^^ doSomething(); } `, - errors: [ - { - message: `Add a "yield" statement to this generator.`, - line: 2, - endLine: 2, - column: 23, - endColumn: 31, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Add a "yield" statement to this generator.`, + line: 2, + endLine: 2, + column: 23, + endColumn: 31, + }, + ], + }, + { + code: ` var foo = function * bar () { doSomething(); } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` function * foo() { // Noncompliant // ^^^ function * bar() { // OK @@ -98,38 +99,39 @@ describe('S3531', () => { } } `, - errors: [ - { - message: `Add a "yield" statement to this generator.`, - line: 2, - endLine: 2, - column: 24, - endColumn: 27, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Add a "yield" statement to this generator.`, + line: 2, + endLine: 2, + column: 24, + endColumn: 27, + }, + ], + }, + { + code: ` class A { *foo() { doSomething(); } } `, - errors: [ - { - message: `Add a "yield" statement to this generator.`, - line: 3, - endLine: 3, - column: 16, - endColumn: 19, - }, - ], - }, - ], - }; + errors: [ + { + message: `Add a "yield" statement to this generator.`, + line: 3, + endLine: 3, + column: 16, + endColumn: 19, + }, + ], + }, + ], + }; - ruleTester.run('Generator without yield', rule, testCases); + ruleTester.run('Generator without yield', rule, testCases); - ruleTesterTs.run('Generator without yield TypeScript', rule, testCases); + ruleTesterTs.run('Generator without yield TypeScript', rule, testCases); + }); }); diff --git a/packages/jsts/src/rules/S3533/unit.test.ts b/packages/jsts/src/rules/S3533/unit.test.ts index d2fbbd431f..4b0571381e 100644 --- a/packages/jsts/src/rules/S3533/unit.test.ts +++ b/packages/jsts/src/rules/S3533/unit.test.ts @@ -16,162 +16,164 @@ */ import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3533', () => { - const ruleTesterJs = new DefaultParserRuleTester(); - ruleTesterJs.run('No require or define import [js]', rule, { - valid: [], - invalid: [ - { - code: `const circle = require('./circle.js');`, - errors: 1, - }, - ], - }); + it('S3533', () => { + const ruleTesterJs = new DefaultParserRuleTester(); + ruleTesterJs.run('No require or define import [js]', rule, { + valid: [], + invalid: [ + { + code: `const circle = require('./circle.js');`, + errors: 1, + }, + ], + }); - const ruleTesterTs = new RuleTester(); - ruleTesterTs.run('No require or define import [ts]', rule, { - valid: [ - { - code: ` + const ruleTesterTs = new RuleTester(); + ruleTesterTs.run('No require or define import [ts]', rule, { + valid: [ + { + code: ` require = 42; if (isArray(require)) { // ... } `, - }, - { - code: ` + }, + { + code: ` exports.area = function (r) { return PI * r * r; }; `, - }, - { - code: ` + }, + { + code: ` module.exports = function(a) { return a * a; } `, - }, - { - code: ` + }, + { + code: ` import A from "ModuleName"; `, - }, - { - code: ` + }, + { + code: ` import { member as alias } from "module-name"; `, - }, - { - code: ` + }, + { + code: ` if (cond) { require('./module.js'); // Ignore non global "imports" } `, - }, - { - code: ` + }, + { + code: ` define(1, 2); // OK, last argument is not function `, - }, - { - code: ` + }, + { + code: ` define(function() { // ... }); // OK, only 1 argument `, - }, - { - code: ` + }, + { + code: ` unknown.define("hello", function() { // ... }); // OK, unknown object `, - }, - { - code: ` + }, + { + code: ` require(1); // not string argument `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` define(["./cart", "./horse"], function(cart, horse) { // ... }); `, - errors: [ - { - message: `Use a standard "import" statement instead of \"define\".`, - line: 2, - endLine: 2, - column: 13, - endColumn: 19, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Use a standard "import" statement instead of \"define\".`, + line: 2, + endLine: 2, + column: 13, + endColumn: 19, + }, + ], + }, + { + code: ` require(["./m1", "./m2"], function(m1, m2) { // ... }); `, - errors: [ - { - message: `Use a standard "import" statement instead of \"require\".`, - line: 2, - endLine: 2, - column: 13, - endColumn: 20, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Use a standard "import" statement instead of \"require\".`, + line: 2, + endLine: 2, + column: 13, + endColumn: 20, + }, + ], + }, + { + code: ` define("ModuleName", [], function(){ // ... }); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` define("ModuleName", [], (a) => {return a}); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` function foo(){ // ... } define("ModuleName", [], foo); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const circle = require('./circle.js'); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const square = require('./squire.js'); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` let str = './squire.js'; const square = require(str); `, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3579/unit.test.ts b/packages/jsts/src/rules/S3579/unit.test.ts index b6656babbe..5f84d53575 100644 --- a/packages/jsts/src/rules/S3579/unit.test.ts +++ b/packages/jsts/src/rules/S3579/unit.test.ts @@ -16,84 +16,86 @@ */ import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3579', () => { - const ruleTesterTs = new RuleTester(); - const ruleTesterJs = new DefaultParserRuleTester(); + it('S3579', () => { + const ruleTesterTs = new RuleTester(); + const ruleTesterJs = new DefaultParserRuleTester(); - ruleTesterTs.run('Array indexes should be numeric [TS]', rule, { - valid: [ - { - code: ` + ruleTesterTs.run('Array indexes should be numeric [TS]', rule, { + valid: [ + { + code: ` const arr = []; arr[0] = 'a';`, - }, - { - code: ` + }, + { + code: ` const car = { type : "Fiat", model : "500", color : "white" }; car["type"] = "BMW"; // OK`, - }, - { - code: ` + }, + { + code: ` let person = new Object(); person["lastname"] = "Ben"`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const arr = []; arr['name'] = 'bob'`, - errors: [ - { - message: `Make it an object if it must have named properties; otherwise, use a numeric index here.`, - line: 3, - column: 7, - endLine: 3, - endColumn: 26, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Make it an object if it must have named properties; otherwise, use a numeric index here.`, + line: 3, + column: 7, + endLine: 3, + endColumn: 26, + }, + ], + }, + { + code: ` const arr = []; const strVar = 'foo'; arr[strVar] = 42`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const arr = new Array(); arr["foo"] = 42`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const fn = () => [1, 2, 3]; fn()["foo"] = 42`, - errors: 1, - }, - ], - }); + errors: 1, + }, + ], + }); - ruleTesterJs.run('Array indexes should be numeric [JS]', rule, { - valid: [ - { - code: ` + ruleTesterJs.run('Array indexes should be numeric [JS]', rule, { + valid: [ + { + code: ` let arr = []; arr[0] = 'a';`, - }, - { - code: ` + }, + { + code: ` let arr = []; arr['name'] = 'bob'`, // issue not raised because no types are available - }, - ], - invalid: [], + }, + ], + invalid: [], + }); }); }); diff --git a/packages/jsts/src/rules/S3616/unit.test.ts b/packages/jsts/src/rules/S3616/unit.test.ts index 8b7f2cead6..16c7653ad1 100644 --- a/packages/jsts/src/rules/S3616/unit.test.ts +++ b/packages/jsts/src/rules/S3616/unit.test.ts @@ -16,14 +16,15 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3616', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Comma and logical OR operators should not be used in switch cases', rule, { - valid: [ - { - code: `switch (a) { + it('S3616', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Comma and logical OR operators should not be used in switch cases', rule, { + valid: [ + { + code: `switch (a) { case 0: // OK case 1: // OK case "a" && "b": // OK, no logical or @@ -32,15 +33,15 @@ describe('S3616', () => { foo2(); break; }`, - }, - { - code: `switch (true) { + }, + { + code: `switch (true) { case cond1() || cond2(): break; }`, - }, - { - code: `switch (a) { + }, + { + code: `switch (a) { case 2: switch (true) { case cond3() || cond4(): @@ -48,11 +49,11 @@ describe('S3616', () => { } break; }`, - }, - ], - invalid: [ - { - code: `switch (a) { + }, + ], + invalid: [ + { + code: `switch (a) { case 2,3: // Noncompliant foo2(); break; @@ -65,35 +66,35 @@ describe('S3616', () => { default: foo4(); }`, - errors: [ - { - message: - 'Explicitly specify 2 separate cases that fall through; currently this case clause only works for "3".', - line: 2, - endLine: 2, - column: 19, - endColumn: 22, - }, - { - message: - 'Explicitly specify 4 separate cases that fall through; currently this case clause only works for "d".', - line: 5, - endLine: 5, - column: 19, - endColumn: 34, - }, - { - message: - 'Explicitly specify 2 separate cases that fall through; currently this case clause only works for "baz()".', - line: 8, - endLine: 8, - column: 19, - endColumn: 31, - }, - ], - }, - { - code: `switch (a) { + errors: [ + { + message: + 'Explicitly specify 2 separate cases that fall through; currently this case clause only works for "3".', + line: 2, + endLine: 2, + column: 19, + endColumn: 22, + }, + { + message: + 'Explicitly specify 4 separate cases that fall through; currently this case clause only works for "d".', + line: 5, + endLine: 5, + column: 19, + endColumn: 34, + }, + { + message: + 'Explicitly specify 2 separate cases that fall through; currently this case clause only works for "baz()".', + line: 8, + endLine: 8, + column: 19, + endColumn: 31, + }, + ], + }, + { + code: `switch (a) { case 2 || 3: // Noncompliant foo2(); break; @@ -106,35 +107,35 @@ describe('S3616', () => { default: foo4(); }`, - errors: [ - { - message: - 'Explicitly specify 2 separate cases that fall through; currently this case clause only works for "2".', - line: 2, - endLine: 2, - column: 19, - endColumn: 25, - }, - { - message: - 'Explicitly specify 4 separate cases that fall through; currently this case clause only works for "a".', - line: 5, - endLine: 5, - column: 19, - endColumn: 43, - }, - { - message: - 'Explicitly specify 2 separate cases that fall through; currently this case clause only works for "bar()".', - line: 8, - endLine: 8, - column: 19, - endColumn: 33, - }, - ], - }, - { - code: `switch (true) { + errors: [ + { + message: + 'Explicitly specify 2 separate cases that fall through; currently this case clause only works for "2".', + line: 2, + endLine: 2, + column: 19, + endColumn: 25, + }, + { + message: + 'Explicitly specify 4 separate cases that fall through; currently this case clause only works for "a".', + line: 5, + endLine: 5, + column: 19, + endColumn: 43, + }, + { + message: + 'Explicitly specify 2 separate cases that fall through; currently this case clause only works for "bar()".', + line: 8, + endLine: 8, + column: 19, + endColumn: 33, + }, + ], + }, + { + code: `switch (true) { case cond1() || cond2(): switch (a) { case cond3() || cond4(): @@ -142,8 +143,9 @@ describe('S3616', () => { } break; }`, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3626/unit.test.ts b/packages/jsts/src/rules/S3626/unit.test.ts index 146ae36637..b7ea0c2088 100644 --- a/packages/jsts/src/rules/S3626/unit.test.ts +++ b/packages/jsts/src/rules/S3626/unit.test.ts @@ -16,36 +16,37 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3626', () => { - const ruleTester = new RuleTester(); + it('S3626', () => { + const ruleTester = new RuleTester(); - ruleTester.run('Jump statements should not be redundant', rule, { - invalid: [ - { - code: `while (x == 1) { + ruleTester.run('Jump statements should not be redundant', rule, { + invalid: [ + { + code: `while (x == 1) { console.log("x == 1"); continue; // Noncompliant }`, - errors: [ - { - messageId: 'removeRedundantJump', - line: 3, - endLine: 3, - suggestions: [ - { - messageId: 'suggestJumpRemoval', - output: `while (x == 1) { + errors: [ + { + messageId: 'removeRedundantJump', + line: 3, + endLine: 3, + suggestions: [ + { + messageId: 'suggestJumpRemoval', + output: `while (x == 1) { console.log("x == 1"); // Noncompliant }`, - }, - ], - }, - ], - }, - { - code: `function redundantJump(condition1, condition2) { + }, + ], + }, + ], + }, + { + code: `function redundantJump(condition1, condition2) { while (condition1) { if (condition2) { console.log("Hello"); @@ -55,15 +56,15 @@ describe('S3626', () => { } } }`, - errors: [ - { - messageId: 'removeRedundantJump', - line: 5, - endLine: 5, - suggestions: [ - { - messageId: 'suggestJumpRemoval', - output: `function redundantJump(condition1, condition2) { + errors: [ + { + messageId: 'removeRedundantJump', + line: 5, + endLine: 5, + suggestions: [ + { + messageId: 'suggestJumpRemoval', + output: `function redundantJump(condition1, condition2) { while (condition1) { if (condition2) { console.log("Hello"); // Noncompliant @@ -72,13 +73,13 @@ describe('S3626', () => { } } }`, - }, - ], - }, - ], - }, - { - code: `function redundantJump(condition1, condition2) { + }, + ], + }, + ], + }, + { + code: `function redundantJump(condition1, condition2) { while (condition1) { if (condition2) { console.log("then"); @@ -88,15 +89,15 @@ describe('S3626', () => { } } }`, - errors: [ - { - messageId: 'removeRedundantJump', - line: 7, - endLine: 7, - suggestions: [ - { - messageId: 'suggestJumpRemoval', - output: `function redundantJump(condition1, condition2) { + errors: [ + { + messageId: 'removeRedundantJump', + line: 7, + endLine: 7, + suggestions: [ + { + messageId: 'suggestJumpRemoval', + output: `function redundantJump(condition1, condition2) { while (condition1) { if (condition2) { console.log("then"); @@ -105,143 +106,143 @@ describe('S3626', () => { } } }`, - }, - ], - }, - ], - }, - { - code: `function redundantJump() { + }, + ], + }, + ], + }, + { + code: `function redundantJump() { for (let i = 0; i < 10; i++) { console.log("Hello"); continue; // Noncompliant } }`, - errors: [ - { - messageId: 'removeRedundantJump', - line: 4, - endLine: 4, - suggestions: [ - { - messageId: 'suggestJumpRemoval', - output: `function redundantJump() { + errors: [ + { + messageId: 'removeRedundantJump', + line: 4, + endLine: 4, + suggestions: [ + { + messageId: 'suggestJumpRemoval', + output: `function redundantJump() { for (let i = 0; i < 10; i++) { console.log("Hello"); // Noncompliant } }`, - }, - ], - }, - ], - }, - { - code: `function redundantJump(b) { + }, + ], + }, + ], + }, + { + code: `function redundantJump(b) { if (b) { console.log("b"); return; // Noncompliant } }`, - errors: [ - { - messageId: 'removeRedundantJump', - line: 4, - endLine: 4, - suggestions: [ - { - messageId: 'suggestJumpRemoval', - output: `function redundantJump(b) { + errors: [ + { + messageId: 'removeRedundantJump', + line: 4, + endLine: 4, + suggestions: [ + { + messageId: 'suggestJumpRemoval', + output: `function redundantJump(b) { if (b) { console.log("b"); // Noncompliant } }`, - }, - ], - }, - ], - }, - { - code: `function redundantJump(x) { + }, + ], + }, + ], + }, + { + code: `function redundantJump(x) { console.log("x == 1"); return; // Noncompliant }`, - errors: [ - { - messageId: 'removeRedundantJump', - line: 3, - endLine: 3, - suggestions: [ - { - messageId: 'suggestJumpRemoval', - output: `function redundantJump(x) { + errors: [ + { + messageId: 'removeRedundantJump', + line: 3, + endLine: 3, + suggestions: [ + { + messageId: 'suggestJumpRemoval', + output: `function redundantJump(x) { console.log("x == 1"); // Noncompliant }`, - }, - ], - }, - ], - }, - { - code: `const redundantJump = (x) => { + }, + ], + }, + ], + }, + { + code: `const redundantJump = (x) => { console.log("x == 1"); return; // Noncompliant }`, - errors: [ - { - messageId: 'removeRedundantJump', - line: 3, - endLine: 3, - suggestions: [ - { - messageId: 'suggestJumpRemoval', - output: `const redundantJump = (x) => { + errors: [ + { + messageId: 'removeRedundantJump', + line: 3, + endLine: 3, + suggestions: [ + { + messageId: 'suggestJumpRemoval', + output: `const redundantJump = (x) => { console.log("x == 1"); // Noncompliant }`, - }, - ], - }, - ], - }, - { - code: `function foo(x) { console.log(x); return; }`, - errors: [ - { - messageId: 'removeRedundantJump', - suggestions: [ - { messageId: 'suggestJumpRemoval', output: `function foo(x) { console.log(x); }` }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: `function foo(x) { console.log(x); return; }`, + errors: [ + { + messageId: 'removeRedundantJump', + suggestions: [ + { messageId: 'suggestJumpRemoval', output: `function foo(x) { console.log(x); }` }, + ], + }, + ], + }, + { + code: ` function foo(x) { console.log(x); // comment1 // comment2 return; }`, - errors: [ - { - messageId: 'removeRedundantJump', - suggestions: [ - { - messageId: 'suggestJumpRemoval', - output: ` + errors: [ + { + messageId: 'removeRedundantJump', + suggestions: [ + { + messageId: 'suggestJumpRemoval', + output: ` function foo(x) { console.log(x); // comment1 // comment2 }`, - }, - ], - }, - ], - }, - ], - valid: [ - { - code: ` + }, + ], + }, + ], + }, + ], + valid: [ + { + code: ` function return_with_value() { foo(); return 42; @@ -292,7 +293,8 @@ function foo(x) { return; // Ok, we ignore when 1 statement } `, - }, - ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3686/unit.test.ts b/packages/jsts/src/rules/S3686/unit.test.ts index ac34135b51..40ba03caa5 100644 --- a/packages/jsts/src/rules/S3686/unit.test.ts +++ b/packages/jsts/src/rules/S3686/unit.test.ts @@ -16,78 +16,80 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3686', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Functions should not be called both with and without "new"', rule, { - valid: [ - { - code: `function foo(){ } + it('S3686', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Functions should not be called both with and without "new"', rule, { + valid: [ + { + code: `function foo(){ } foo(); foo(1);`, - }, - { - code: `function foo(){ } + }, + { + code: `function foo(){ } new foo(); new foo(1);`, - }, - { - code: `function bar() { + }, + { + code: `function bar() { function bar() {} var a = new bar(); } var b = bar(); // OK`, - }, - { - code: ` + }, + { + code: ` Number(x); new Number(x);`, - }, - { - code: `const a = new A(); + }, + { + code: `const a = new A(); a.foo(); new a.foo();`, - }, - ], - invalid: [ - { - code: `var x = external(); + }, + ], + invalid: [ + { + code: `var x = external(); x(); x(); var xx = new x(); x();`, - errors: [ - { - message: - '{"message":"Correct the use of this function; on line 3 it was called without \\"new\\".","secondaryLocations":[{"column":14,"line":3,"endColumn":15,"endLine":3}]}', - line: 4, - endLine: 4, - column: 28, - endColumn: 29, - }, - ], - options: ['sonar-runtime'], - }, - { - code: `function MyObj() { } + errors: [ + { + message: + '{"message":"Correct the use of this function; on line 3 it was called without \\"new\\".","secondaryLocations":[{"column":14,"line":3,"endColumn":15,"endLine":3}]}', + line: 4, + endLine: 4, + column: 28, + endColumn: 29, + }, + ], + options: ['sonar-runtime'], + }, + { + code: `function MyObj() { } var obj = new MyObj(); MyObj(); // Noncompliant obj = new MyObj(); MyObj();`, - errors: [ - { - message: - '{"message":"Correct the use of this function; on line 2 it was called with \\"new\\".","secondaryLocations":[{"column":30,"line":2,"endColumn":35,"endLine":2}]}', - line: 3, - endLine: 3, - column: 17, - endColumn: 22, - }, - ], - options: ['sonar-runtime'], - }, - ], + errors: [ + { + message: + '{"message":"Correct the use of this function; on line 2 it was called with \\"new\\".","secondaryLocations":[{"column":30,"line":2,"endColumn":35,"endLine":2}]}', + line: 3, + endLine: 3, + column: 17, + endColumn: 22, + }, + ], + options: ['sonar-runtime'], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3696/unit.test.ts b/packages/jsts/src/rules/S3696/unit.test.ts index 70a9fc37a7..6add2019e9 100644 --- a/packages/jsts/src/rules/S3696/unit.test.ts +++ b/packages/jsts/src/rules/S3696/unit.test.ts @@ -16,61 +16,65 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3696', () => { - const ruleTester = new RuleTester(); + it('S3696', () => { + const ruleTester = new RuleTester(); - ruleTester.run(`Decorated rule should provide suggestion`, rule, { - valid: [ - { - code: `{ throw new Error('foo'); }`, - }, - ], - invalid: [ - { - code: `{ throw 'foo'; }`, - errors: [ - { - message: 'Expected an error object to be thrown.', - suggestions: [{ output: `{ throw new Error('foo'); }`, desc: 'Throw an error object' }], - }, - ], - }, - { - code: `{ throw 'foo' + bar(); }`, - errors: [ - { - message: 'Expected an error object to be thrown.', - suggestions: [ - { output: `{ throw new Error('foo' + bar()); }`, desc: 'Throw an error object' }, - ], - }, - ], - }, - { - code: `{ throw foo() + 'bar'; }`, - errors: [ - { - message: 'Expected an error object to be thrown.', - suggestions: [ - { output: `{ throw new Error(foo() + 'bar'); }`, desc: 'Throw an error object' }, - ], - }, - ], - }, - { - code: `{ throw 1; }`, - errors: [{ message: 'Expected an error object to be thrown.', suggestions: [] }], - }, - { - code: `{ throw undefined; }`, - errors: [{ message: 'Do not throw undefined.', suggestions: [] }], - }, - { - code: `{ throw 1 + 2; }`, - errors: [{ message: 'Expected an error object to be thrown.', suggestions: [] }], - }, - ], + ruleTester.run(`Decorated rule should provide suggestion`, rule, { + valid: [ + { + code: `{ throw new Error('foo'); }`, + }, + ], + invalid: [ + { + code: `{ throw 'foo'; }`, + errors: [ + { + message: 'Expected an error object to be thrown.', + suggestions: [ + { output: `{ throw new Error('foo'); }`, desc: 'Throw an error object' }, + ], + }, + ], + }, + { + code: `{ throw 'foo' + bar(); }`, + errors: [ + { + message: 'Expected an error object to be thrown.', + suggestions: [ + { output: `{ throw new Error('foo' + bar()); }`, desc: 'Throw an error object' }, + ], + }, + ], + }, + { + code: `{ throw foo() + 'bar'; }`, + errors: [ + { + message: 'Expected an error object to be thrown.', + suggestions: [ + { output: `{ throw new Error(foo() + 'bar'); }`, desc: 'Throw an error object' }, + ], + }, + ], + }, + { + code: `{ throw 1; }`, + errors: [{ message: 'Expected an error object to be thrown.', suggestions: [] }], + }, + { + code: `{ throw undefined; }`, + errors: [{ message: 'Do not throw undefined.', suggestions: [] }], + }, + { + code: `{ throw 1 + 2; }`, + errors: [{ message: 'Expected an error object to be thrown.', suggestions: [] }], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3699/unit.test.ts b/packages/jsts/src/rules/S3699/unit.test.ts index 701b2c76d0..38ba5f2f87 100644 --- a/packages/jsts/src/rules/S3699/unit.test.ts +++ b/packages/jsts/src/rules/S3699/unit.test.ts @@ -16,91 +16,93 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3699', () => { - const ruleTester = new RuleTester(); + it('S3699', () => { + const ruleTester = new RuleTester(); - const FUNCTION_NO_RETURN = 'function noReturn() { }\n '; + const FUNCTION_NO_RETURN = 'function noReturn() { }\n '; - ruleTester.run('no-use-of-empty-return-value', rule, { - valid: [ - { code: 'function withReturn() { return 1; } console.log(withReturn());' }, - { code: 'let x = () => {}; if (cond) {x = () => 1} let y = x();' }, - { code: 'var x = function x() { return 42 }; y = x();' }, - { code: FUNCTION_NO_RETURN + 'noReturn();' }, - { code: FUNCTION_NO_RETURN + 'async function foo() { await noReturn(); }' }, - { code: FUNCTION_NO_RETURN + 'function foo() { return noReturn(); }' }, - { code: FUNCTION_NO_RETURN + '(noReturn());' }, - { code: FUNCTION_NO_RETURN + 'let arrowFunc = p => noReturn();' }, - { code: FUNCTION_NO_RETURN + 'let arrowFunc = p => (noReturn());' }, - { code: FUNCTION_NO_RETURN + 'cond ? noReturn() : somethingElse();' }, - { code: FUNCTION_NO_RETURN + 'boolVar && noReturn();' }, - { code: FUNCTION_NO_RETURN + 'boolVar || noReturn();' }, - { code: 'function noReturn() { return; }; noReturn();' }, - { code: 'function withReturn() { return 42; }; x = noReturn();' }, - { code: '(function(){}());' }, - { code: '!function(){}();' }, - { code: 'class A { methodNoReturn() {}\n foo() { console.log(this.methodNoReturn()); } }' }, // FN - { code: 'var arrowImplicitReturn = (a) => a*2; x = arrowImplicitReturn(1);' }, - { - code: 'var arrowReturnsPromise = async () => { var x = () => {return 1} }; x = arrowReturnsPromise();', - }, - { - code: 'async function statementReturnsPromise() { var x = () => {return 1} }\n x = statementReturnsPromise();', - }, - { code: 'function* noReturn() { yield 1; } noReturn().next();' }, - { code: 'function* noReturn() { yield 1; } noReturn();' }, - { code: 'declare function withReturn(): number; let x = withReturn();' }, - ], - invalid: [ - invalidPrefixWithFunction('console.log(noReturn());'), - invalidPrefixWithFunction('x = noReturn();'), - invalidPrefixWithFunction('noReturn() ? foo() : bar();'), - invalidPrefixWithFunction('noReturn().foo();'), - invalidPrefixWithFunction('let x = noReturn();'), - invalidPrefixWithFunction('for (var x in noReturn()) { }'), - invalidPrefixWithFunction('for (var x of noReturn()) { }'), - invalidPrefixWithFunction('noReturn() && doSomething();'), - invalid('var noReturn = function () { 1; }; console.log(noReturn());'), - invalid('var noReturn = () => { 42;}; console.log(noReturn());'), - invalid('function noReturn() { return; }; console.log(noReturn());'), - invalid( - 'var noReturn = function () { let x = () => { return 42 }; }; console.log(noReturn());', - ), - invalid('var funcExpr = function noReturn () { 1; console.log(noReturn()); };'), - invalid('var noReturn = () => { var x = () => {return 1} }; x = noReturn();'), - invalid('declare function noReturn(): never; let x = noReturn();'), - invalid('declare function noReturn(): void; let x = noReturn();'), - invalid('declare function noReturn(): undefined; let x = noReturn();'), - ], - }); - - function invalidPrefixWithFunction(code: string, functionName: string = 'noReturn') { - return { - code: 'function noReturn() { 1;} ' + code, - errors: [ + ruleTester.run('no-use-of-empty-return-value', rule, { + valid: [ + { code: 'function withReturn() { return 1; } console.log(withReturn());' }, + { code: 'let x = () => {}; if (cond) {x = () => 1} let y = x();' }, + { code: 'var x = function x() { return 42 }; y = x();' }, + { code: FUNCTION_NO_RETURN + 'noReturn();' }, + { code: FUNCTION_NO_RETURN + 'async function foo() { await noReturn(); }' }, + { code: FUNCTION_NO_RETURN + 'function foo() { return noReturn(); }' }, + { code: FUNCTION_NO_RETURN + '(noReturn());' }, + { code: FUNCTION_NO_RETURN + 'let arrowFunc = p => noReturn();' }, + { code: FUNCTION_NO_RETURN + 'let arrowFunc = p => (noReturn());' }, + { code: FUNCTION_NO_RETURN + 'cond ? noReturn() : somethingElse();' }, + { code: FUNCTION_NO_RETURN + 'boolVar && noReturn();' }, + { code: FUNCTION_NO_RETURN + 'boolVar || noReturn();' }, + { code: 'function noReturn() { return; }; noReturn();' }, + { code: 'function withReturn() { return 42; }; x = noReturn();' }, + { code: '(function(){}());' }, + { code: '!function(){}();' }, + { code: 'class A { methodNoReturn() {}\n foo() { console.log(this.methodNoReturn()); } }' }, // FN + { code: 'var arrowImplicitReturn = (a) => a*2; x = arrowImplicitReturn(1);' }, { - messageId: 'removeUseOfOutput', - data: { - name: functionName, - }, + code: 'var arrowReturnsPromise = async () => { var x = () => {return 1} }; x = arrowReturnsPromise();', }, - ], - }; - } - - function invalid(code: string) { - return { - code, - errors: [ { - messageId: 'removeUseOfOutput', - data: { - name: 'noReturn', - }, + code: 'async function statementReturnsPromise() { var x = () => {return 1} }\n x = statementReturnsPromise();', }, + { code: 'function* noReturn() { yield 1; } noReturn().next();' }, + { code: 'function* noReturn() { yield 1; } noReturn();' }, + { code: 'declare function withReturn(): number; let x = withReturn();' }, ], - }; - } + invalid: [ + invalidPrefixWithFunction('console.log(noReturn());'), + invalidPrefixWithFunction('x = noReturn();'), + invalidPrefixWithFunction('noReturn() ? foo() : bar();'), + invalidPrefixWithFunction('noReturn().foo();'), + invalidPrefixWithFunction('let x = noReturn();'), + invalidPrefixWithFunction('for (var x in noReturn()) { }'), + invalidPrefixWithFunction('for (var x of noReturn()) { }'), + invalidPrefixWithFunction('noReturn() && doSomething();'), + invalid('var noReturn = function () { 1; }; console.log(noReturn());'), + invalid('var noReturn = () => { 42;}; console.log(noReturn());'), + invalid('function noReturn() { return; }; console.log(noReturn());'), + invalid( + 'var noReturn = function () { let x = () => { return 42 }; }; console.log(noReturn());', + ), + invalid('var funcExpr = function noReturn () { 1; console.log(noReturn()); };'), + invalid('var noReturn = () => { var x = () => {return 1} }; x = noReturn();'), + invalid('declare function noReturn(): never; let x = noReturn();'), + invalid('declare function noReturn(): void; let x = noReturn();'), + invalid('declare function noReturn(): undefined; let x = noReturn();'), + ], + }); + + function invalidPrefixWithFunction(code: string, functionName: string = 'noReturn') { + return { + code: 'function noReturn() { 1;} ' + code, + errors: [ + { + messageId: 'removeUseOfOutput', + data: { + name: functionName, + }, + }, + ], + }; + } + + function invalid(code: string) { + return { + code, + errors: [ + { + messageId: 'removeUseOfOutput', + data: { + name: 'noReturn', + }, + }, + ], + }; + } + }); }); diff --git a/packages/jsts/src/rules/S3723/unit.test.ts b/packages/jsts/src/rules/S3723/unit.test.ts index 3cb583f3da..3002dcd100 100644 --- a/packages/jsts/src/rules/S3723/unit.test.ts +++ b/packages/jsts/src/rules/S3723/unit.test.ts @@ -16,34 +16,36 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3723', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Trailing commas should be used', rule, { - valid: [ - { - code: ` + it('S3723', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Trailing commas should be used', rule, { + valid: [ + { + code: ` obj = { foo: 42, bar: 24 }; `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` obj = { foo: 42, bar: 24, };`, - errors: 1, - output: ` + errors: 1, + output: ` obj = { foo: 42, bar: 24 };`, - }, - ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3735/unit.test.ts b/packages/jsts/src/rules/S3735/unit.test.ts index 8dcf4991ac..2f0caf4712 100644 --- a/packages/jsts/src/rules/S3735/unit.test.ts +++ b/packages/jsts/src/rules/S3735/unit.test.ts @@ -16,90 +16,92 @@ */ import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3735', () => { - const ruleTesterJs = new DefaultParserRuleTester(); - const ruleTesterTs = new RuleTester(); + it('S3735', () => { + const ruleTesterJs = new DefaultParserRuleTester(); + const ruleTesterTs = new RuleTester(); - ruleTesterJs.run('"void" should not be used JS', rule, { - valid: [ - { - code: ` + ruleTesterJs.run('"void" should not be used JS', rule, { + valid: [ + { + code: ` (function() { })() `, - }, - { - code: ` + }, + { + code: ` void 0; `, - }, - { - code: ` + }, + { + code: ` void (0); `, - }, - { - code: ` + }, + { + code: ` void function() { }() `, - }, - { - code: ` + }, + { + code: ` void (() => 42) () `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` foo(void 42); `, - errors: [ - { - message: `Remove this use of the \"void\" operator.`, - line: 2, - endLine: 2, - column: 17, - endColumn: 21, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Remove this use of the \"void\" operator.`, + line: 2, + endLine: 2, + column: 17, + endColumn: 21, + }, + ], + }, + { + code: ` const f = () => { return new Promise(() => {}); }; void f(); // FP: should be ignored since 'f()' is a promise but we are missing type information `, - errors: 1, - }, - ], - }); + errors: 1, + }, + ], + }); - ruleTesterTs.run('"void" should not be used TS', rule, { - valid: [ - { - code: `void 0;`, - }, - { - code: ` + ruleTesterTs.run('"void" should not be used TS', rule, { + valid: [ + { + code: `void 0;`, + }, + { + code: ` const p = new Promise(() => {}); void p; `, - }, - { - code: ` + }, + { + code: ` const f = () => { return new Promise(() => {}); }; void f(); `, - }, - ], - invalid: [ - { - code: `void 42;`, - errors: 1, - }, - ], + }, + ], + invalid: [ + { + code: `void 42;`, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3757/unit.test.ts b/packages/jsts/src/rules/S3757/unit.test.ts index b75f19704a..8a0c4c3911 100644 --- a/packages/jsts/src/rules/S3757/unit.test.ts +++ b/packages/jsts/src/rules/S3757/unit.test.ts @@ -16,37 +16,38 @@ */ import { rule } from './index.js'; import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3757', () => { - const ruleTesterJs = new DefaultParserRuleTester(); - ruleTesterJs.run('Arithmetic operation returning NaN [NoParserServices]', rule, { - valid: [ - { - code: ` + it('S3757', () => { + const ruleTesterJs = new DefaultParserRuleTester(); + ruleTesterJs.run('Arithmetic operation returning NaN [NoParserServices]', rule, { + valid: [ + { + code: ` let x = 42 - [1,2]; `, - }, - ], - invalid: [], - }); + }, + ], + invalid: [], + }); - const ruleTester = new RuleTester(); - ruleTester.run('Arithmetic operation returning NaN', rule, { - valid: [ - { - code: ` + const ruleTester = new RuleTester(); + ruleTester.run('Arithmetic operation returning NaN', rule, { + valid: [ + { + code: ` let x = 42 - 7; `, - }, - { - code: ` + }, + { + code: ` var obj1 = {} obj1 + 42; // concatenation `, - }, - { - code: ` + }, + { + code: ` function dates() { var date1 = new Date(); var date2 = new Date(); @@ -57,78 +58,79 @@ describe('S3757', () => { 42 / new Date(); // ok } `, - }, - { - code: ` + }, + { + code: ` null + 42; // ok true + 42; // ok `, - }, - { - code: ` + }, + { + code: ` typeof {} == 'string'; `, - }, - { - code: ` + }, + { + code: ` function doSomething(something) { if ((typeof something === 'number' || something instanceof Number) && !isFinite(+something)) { console.log("hello"); } } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` let x = 42 - [1,2]; let y = [1,2] - 42; `, - errors: [ - { - message: `Change the expression which uses this operand so that it can't evaluate to "NaN" (Not a Number).`, - line: 2, - column: 22, - endLine: 2, - endColumn: 27, - }, - { - message: `Change the expression which uses this operand so that it can't evaluate to "NaN" (Not a Number).`, - line: 3, - column: 17, - endLine: 3, - endColumn: 22, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Change the expression which uses this operand so that it can't evaluate to "NaN" (Not a Number).`, + line: 2, + column: 22, + endLine: 2, + endColumn: 27, + }, + { + message: `Change the expression which uses this operand so that it can't evaluate to "NaN" (Not a Number).`, + line: 3, + column: 17, + endLine: 3, + endColumn: 22, + }, + ], + }, + { + code: ` var array7 = [1,2]; array7 /= 42; `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` var obj1 = {} obj1 - 42; `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` var array2 = [1,2]; array2--; `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` foo(+[1,2]); `, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3758/unit.test.ts b/packages/jsts/src/rules/S3758/unit.test.ts index 5fb7b22abb..0e32ceb280 100644 --- a/packages/jsts/src/rules/S3758/unit.test.ts +++ b/packages/jsts/src/rules/S3758/unit.test.ts @@ -16,151 +16,153 @@ */ import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3758', () => { - const ruleTesterTs = new RuleTester(); - const ruleTesterJs = new DefaultParserRuleTester(); + it('S3758', () => { + const ruleTesterTs = new RuleTester(); + const ruleTesterJs = new DefaultParserRuleTester(); - ruleTesterTs.run( - 'Values not convertible to numbers should not be used in numeric comparisons [TS]', - rule, - { - valid: [ - { - code: `42 > 41`, - }, - { - code: ` + ruleTesterTs.run( + 'Values not convertible to numbers should not be used in numeric comparisons [TS]', + rule, + { + valid: [ + { + code: `42 > 41`, + }, + { + code: ` const n1 = 42; const n2 = 0; n1 >= 0`, - }, - { - code: ` + }, + { + code: ` const date = new Date(); date > 42; `, - }, - { - code: `42 > NaN`, // FN, - }, - { - code: `"foo" > "hello"`, - }, - { - code: 'true > false', - }, - { - code: ` + }, + { + code: `42 > NaN`, // FN, + }, + { + code: `"foo" > "hello"`, + }, + { + code: 'true > false', + }, + { + code: ` const a = 42 === 42; const b = 'str'; a < b; `, - }, - { - code: `42 > null`, - }, - { - code: `42 > unknown`, - }, - { - code: ` + }, + { + code: `42 > null`, + }, + { + code: `42 > unknown`, + }, + { + code: ` const undef; undef > 42;`, // FN - }, - { - code: `"hello" <= new Object()`, - }, - { - code: ` + }, + { + code: `"hello" <= new Object()`, + }, + { + code: ` var undefinedVariable; var nan = undefinedVariable + 42; nan >= 42;`, // FN - }, - { - code: ` + }, + { + code: ` let x = { }; x.a >= 42;`, // FN - }, - { - code: ` + }, + { + code: ` const a = BigInt("42"); const b = BigInt("41"); a > b; `, - }, - { - code: ` + }, + { + code: ` const a = 42n; const b = 41n; a > b; `, - }, - { - code: ` + }, + { + code: ` const a = BigInt("42"); const b = 41n; a > b; `, - }, - ], - invalid: [ - { - code: `new Object() > 0`, - errors: [ - { - message: - 'Re-evaluate the data flow; this operand of a numeric comparison could be of type Object.', - line: 1, - endLine: 1, - column: 1, - endColumn: 13, - }, - ], - }, - { - code: ` + }, + ], + invalid: [ + { + code: `new Object() > 0`, + errors: [ + { + message: + 'Re-evaluate the data flow; this operand of a numeric comparison could be of type Object.', + line: 1, + endLine: 1, + column: 1, + endColumn: 13, + }, + ], + }, + { + code: ` const obj1 = new Object(); const obj2 = new Object(); obj1 < obj2;`, - errors: 2, - }, - { - code: `42 > undefined`, - errors: [ - { - message: - 'Re-evaluate the data flow; this operand of a numeric comparison could be of type undefined.', - }, - ], - }, - { - code: `1 < function(){}`, - errors: 1, - }, - { - code: ` + errors: 2, + }, + { + code: `42 > undefined`, + errors: [ + { + message: + 'Re-evaluate the data flow; this operand of a numeric comparison could be of type undefined.', + }, + ], + }, + { + code: `1 < function(){}`, + errors: 1, + }, + { + code: ` var array = [3,2]; array > 42;`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` var obj = {}; obj <= 42;`, - errors: 1, - }, - ], - }, - ); + errors: 1, + }, + ], + }, + ); - ruleTesterJs.run( - 'Values not convertible to numbers should not be used in numeric comparisons [JS]', - rule, - { - valid: [{ code: `new Object() > 0` }], // no type information - invalid: [], - }, - ); + ruleTesterJs.run( + 'Values not convertible to numbers should not be used in numeric comparisons [JS]', + rule, + { + valid: [{ code: `new Object() > 0` }], // no type information + invalid: [], + }, + ); + }); }); diff --git a/packages/jsts/src/rules/S3760/unit.test.ts b/packages/jsts/src/rules/S3760/unit.test.ts index 682e9080a4..3a018f08e8 100644 --- a/packages/jsts/src/rules/S3760/unit.test.ts +++ b/packages/jsts/src/rules/S3760/unit.test.ts @@ -16,29 +16,30 @@ */ import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3760', () => { - const ruleTesterJs = new DefaultParserRuleTester(); - const ruleTesterTs = new RuleTester(); + it('S3760', () => { + const ruleTesterJs = new DefaultParserRuleTester(); + const ruleTesterTs = new RuleTester(); - ruleTesterJs.run('No issues without types', rule, { - valid: [ - { - code: ` + ruleTesterJs.run('No issues without types', rule, { + valid: [ + { + code: ` var num = 42; var bool = true; num + bool; `, - }, - ], - invalid: [], - }); + }, + ], + invalid: [], + }); - ruleTesterTs.run('Arithmetic operators should only have numbers as operands', rule, { - valid: [ - { - code: ` + ruleTesterTs.run('Arithmetic operators should only have numbers as operands', rule, { + valid: [ + { + code: ` function plus() { var str = ""; var bool = true; @@ -79,89 +80,89 @@ describe('S3760', () => { +num; } `, - }, - { - code: ` + }, + { + code: ` var bool = true; if (!bool) { console.log("hello"); } `, - }, - { - code: ` + }, + { + code: ` var num = 42; var other = 43; other = true; num + other; // FN `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` var num = 42; var bool = true; num + bool; `, - errors: [ - { - line: 4, - endLine: 4, - column: 13, - endColumn: 17, - message: JSON.stringify({ - message: 'Convert this operand into a number.', - secondaryLocations: [ - { - column: 6, - line: 4, - endColumn: 9, - endLine: 4, - }, - ], - }), - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + line: 4, + endLine: 4, + column: 13, + endColumn: 17, + message: JSON.stringify({ + message: 'Convert this operand into a number.', + secondaryLocations: [ + { + column: 6, + line: 4, + endColumn: 9, + endLine: 4, + }, + ], + }), + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` var num = 42; var bool = true; num += bool; `, - errors: [ - { - line: 4, - endLine: 4, - column: 14, - endColumn: 18, - message: JSON.stringify({ - message: 'Convert this operand into a number.', - secondaryLocations: [ - { - column: 6, - line: 4, - endColumn: 9, - endLine: 4, - }, - ], - }), - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + line: 4, + endLine: 4, + column: 14, + endColumn: 18, + message: JSON.stringify({ + message: 'Convert this operand into a number.', + secondaryLocations: [ + { + column: 6, + line: 4, + endColumn: 9, + endLine: 4, + }, + ], + }), + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` var num = 42; var bool = true; bool += num; `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` var str = ""; var num = 42; var bool = true; @@ -169,59 +170,59 @@ describe('S3760', () => { str > bool; bool < num; `, - errors: 3, - }, - { - code: ` + errors: 3, + }, + { + code: ` var d1 = new Date(), d2 = new Date(); d1/d2; d1*d2 `, - errors: 2, - }, - { - code: ` + errors: 2, + }, + { + code: ` var d1 = new Date(), d2 = new Date(); d1*=d2; d1-=d2; // OK `, - errors: [ - { - line: 3, - endLine: 3, - column: 7, - endColumn: 13, - message: JSON.stringify({ - message: 'Convert the operands of this operation into numbers.', - secondaryLocations: [ - { - column: 6, - line: 3, - endColumn: 8, - endLine: 3, - }, - { - column: 10, - line: 3, - endColumn: 12, - endLine: 3, - }, - ], - }), - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + line: 3, + endLine: 3, + column: 7, + endColumn: 13, + message: JSON.stringify({ + message: 'Convert the operands of this operation into numbers.', + secondaryLocations: [ + { + column: 6, + line: 3, + endColumn: 8, + endLine: 3, + }, + { + column: 10, + line: 3, + endColumn: 12, + endLine: 3, + }, + ], + }), + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` var d1 = new Date(); var num = 42; d1 - num; // Noncompliant `, - errors: [{ message: 'Convert the operands of this operation into numbers.', line: 4 }], - }, - { - code: ` + errors: [{ message: 'Convert the operands of this operation into numbers.', line: 4 }], + }, + { + code: ` var str = ""; var bool = true; var d1 = new Date(); @@ -232,18 +233,18 @@ describe('S3760', () => { d1++; --d1; `, - errors: 6, - }, - { - code: ` + errors: 6, + }, + { + code: ` var str = "42"; var x = 42; str - 4; // Noncompliant `, - errors: [{ message: 'Convert the operands of this operation into numbers.', line: 4 }], - }, - { - code: ` + errors: [{ message: 'Convert the operands of this operation into numbers.', line: 4 }], + }, + { + code: ` var str = "42"; var x; @@ -254,10 +255,10 @@ describe('S3760', () => { str - 4; // Noncompliant foo(x); `, - errors: [{ message: 'Convert the operands of this operation into numbers.', line: 9 }], - }, - { - code: ` + errors: [{ message: 'Convert the operands of this operation into numbers.', line: 9 }], + }, + { + code: ` function primitive_wrappers(x) { -new String(x); -new Boolean(x); @@ -270,35 +271,36 @@ describe('S3760', () => { "42" > new Number(x); } `, - errors: 9, - }, - { - code: ` + errors: 9, + }, + { + code: ` var num = 42; var other = true; other = 43; num + other; // FP `, - errors: [{ message: 'Convert this operand into a number.', line: 5 }], - }, - { - code: ` + errors: [{ message: 'Convert this operand into a number.', line: 5 }], + }, + { + code: ` expect(something()).toEqual(-'1'); `, - errors: [ - { - message: JSON.stringify({ - message: 'Convert this operand into a number.', - secondaryLocations: [], - }), - line: 2, - endLine: 2, - column: 36, - endColumn: 39, - }, - ], - options: ['sonar-runtime'], - }, - ], + errors: [ + { + message: JSON.stringify({ + message: 'Convert this operand into a number.', + secondaryLocations: [], + }), + line: 2, + endLine: 2, + column: 36, + endColumn: 39, + }, + ], + options: ['sonar-runtime'], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3776/unit.test.ts b/packages/jsts/src/rules/S3776/unit.test.ts index 0ea9c90eb0..7cc0d26e59 100644 --- a/packages/jsts/src/rules/S3776/unit.test.ts +++ b/packages/jsts/src/rules/S3776/unit.test.ts @@ -17,25 +17,26 @@ import { rule } from './index.js'; import type { IssueLocation } from '../helpers/index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3776', () => { - const ruleTester = new RuleTester(); + it('S3776', () => { + const ruleTester = new RuleTester(); - ruleTester.run('cognitive-complexity', rule, { - valid: [ - { code: `function zero_complexity() {}`, options: [0] }, - { - code: ` + ruleTester.run('cognitive-complexity', rule, { + valid: [ + { code: `function zero_complexity() {}`, options: [0] }, + { + code: ` function Component(obj) { return ( { obj.title?.text } ); }`, - options: [0], - }, - { - code: ` + options: [0], + }, + { + code: ` function Component(obj) { return ( <> @@ -43,10 +44,10 @@ describe('S3776', () => { ); }`, - options: [0], - }, - { - code: ` + options: [0], + }, + { + code: ` function Component(obj) { return ( <> @@ -54,10 +55,10 @@ describe('S3776', () => { ); }`, - options: [0], - }, - { - code: ` + options: [0], + }, + { + code: ` function Component(obj) { return ( <> @@ -65,48 +66,48 @@ describe('S3776', () => { ); }`, - options: [0], - }, - { - code: ` + options: [0], + }, + { + code: ` function Component(obj) { return ( Text ); }`, - options: [0], - }, - { - code: ` + options: [0], + }, + { + code: ` function Component(obj) { return ( ); }`, - options: [0], - }, - { - code: ` + options: [0], + }, + { + code: ` function f(a, b, c) { const x = a || []; const y = b || {}; const z = c ?? ''; }`, - options: [0], - }, - { - code: ` + options: [0], + }, + { + code: ` function f(a, b, c) { a = a || []; b = b || {}; c = c ?? ''; }`, - options: [0], - }, - ], - invalid: [ - testCaseWithSonarRuntime( - ` + options: [0], + }, + ], + invalid: [ + testCaseWithSonarRuntime( + ` function check_secondaries() { if (condition) { // +1 "if" if (condition) {} else {} // +2 "if", +1 "else" @@ -126,47 +127,47 @@ describe('S3776', () => { return foo(a && b) && c; // +1 "&&", +1 "&&" }`, - [ - { message: '+1', column: 8, line: 3, endColumn: 10, endLine: 3 }, // if - { message: '+1', column: 10, line: 7, endColumn: 14, endLine: 7 }, // else - { - message: '+2 (incl. 1 for nesting)', - column: 10, - line: 4, - endColumn: 12, - endLine: 4, - }, // if - { message: '+1', column: 28, line: 4, endColumn: 32, endLine: 4 }, // else - { - message: '+2 (incl. 1 for nesting)', - column: 10, - line: 6, - endColumn: 15, - endLine: 6, - }, // catch - { message: '+1', column: 8, line: 11, endColumn: 13, endLine: 11 }, // while - { message: '+1', column: 10, line: 12, endColumn: 15, endLine: 12 }, // break - { message: '+1', column: 10, line: 15, endColumn: 11, endLine: 15 }, // ? - { message: '+1', column: 8, line: 17, endColumn: 14, endLine: 17 }, // switch - { message: '+1', column: 27, line: 19, endColumn: 29, endLine: 19 }, // && - { message: '+1', column: 21, line: 19, endColumn: 23, endLine: 19 }, // && - ], - 13, - ), + [ + { message: '+1', column: 8, line: 3, endColumn: 10, endLine: 3 }, // if + { message: '+1', column: 10, line: 7, endColumn: 14, endLine: 7 }, // else + { + message: '+2 (incl. 1 for nesting)', + column: 10, + line: 4, + endColumn: 12, + endLine: 4, + }, // if + { message: '+1', column: 28, line: 4, endColumn: 32, endLine: 4 }, // else + { + message: '+2 (incl. 1 for nesting)', + column: 10, + line: 6, + endColumn: 15, + endLine: 6, + }, // catch + { message: '+1', column: 8, line: 11, endColumn: 13, endLine: 11 }, // while + { message: '+1', column: 10, line: 12, endColumn: 15, endLine: 12 }, // break + { message: '+1', column: 10, line: 15, endColumn: 11, endLine: 15 }, // ? + { message: '+1', column: 8, line: 17, endColumn: 14, endLine: 17 }, // switch + { message: '+1', column: 27, line: 19, endColumn: 29, endLine: 19 }, // && + { message: '+1', column: 21, line: 19, endColumn: 23, endLine: 19 }, // && + ], + 13, + ), - // expressions - testCaseWithSonarRuntime( - ` + // expressions + testCaseWithSonarRuntime( + ` function and_or_locations() { foo(1 && 2 || 3 && 4); }`, - [ - { message: '+1', column: 14, line: 3, endColumn: 16, endLine: 3 }, // && - { message: '+1', column: 24, line: 3, endColumn: 26, endLine: 3 }, // && - ], - ), - { - code: ` + [ + { message: '+1', column: 14, line: 3, endColumn: 16, endLine: 3 }, // && + { message: '+1', column: 24, line: 3, endColumn: 26, endLine: 3 }, // && + ], + ), + { + code: ` function and_or() { foo(1 && 2 && 3 && 4); // +1 foo((1 && 2) && (3 && 4)); // +1 @@ -177,29 +178,29 @@ describe('S3776', () => { foo(1 && 2 || 3 && 4); // +2 foo(1 && 2 && !(3 && 4)); // +2 }`, - options: [0], - errors: [message(9)], - }, - { - code: ` + options: [0], + errors: [message(9)], + }, + { + code: ` function conditional_expression() { return condition ? trueValue : falseValue; }`, - options: [0], - errors: [message(1)], - }, - { - code: ` + options: [0], + errors: [message(1)], + }, + { + code: ` function nested_conditional_expression() { x = condition1 ? (condition2 ? trueValue2 : falseValue2) : falseValue1 ; // +3 x = condition1 ? trueValue1 : (condition2 ? trueValue2 : falseValue2) ; // +3 x = condition1 ? (condition2 ? trueValue2 : falseValue2) : (condition3 ? trueValue3 : falseValue3); // +5 }`, - options: [0], - errors: [message(11)], - }, - { - code: ` + options: [0], + errors: [message(11)], + }, + { + code: ` function complexity_in_conditions(a, b) { if (a && b) { // +1(if) +1(&&) a && b; // +1 (no nesting) @@ -208,23 +209,23 @@ describe('S3776', () => { do {} while (a && b) // +1(do) +1(&&) for (var i = a && b; a && b; a && b) {} // +1(for) +1(&&) +1(&&) +1(&&) }`, - options: [0], - errors: [message(11)], - }, + options: [0], + errors: [message(11)], + }, - // different function types - { - code: 'var arrowFunction = (a, b) => a && b;', - options: [0], - errors: [message(1, { line: 1, endLine: 1, column: 28, endColumn: 30 })], - }, - { - code: 'var functionExpression = function(a, b) { return a && b; }', - options: [0], - errors: [message(1, { line: 1, endLine: 1, column: 26, endColumn: 34 })], - }, - { - code: ` + // different function types + { + code: 'var arrowFunction = (a, b) => a && b;', + options: [0], + errors: [message(1, { line: 1, endLine: 1, column: 28, endColumn: 30 })], + }, + { + code: 'var functionExpression = function(a, b) { return a && b; }', + options: [0], + errors: [message(1, { line: 1, endLine: 1, column: 26, endColumn: 34 })], + }, + { + code: ` class A { method() { if (condition) { // +1 @@ -232,21 +233,21 @@ describe('S3776', () => { } } }`, - options: [0], - errors: [message(1, { line: 3, endLine: 3, column: 9, endColumn: 15 })], - }, - { - code: ` + options: [0], + errors: [message(1, { line: 3, endLine: 3, column: 9, endColumn: 15 })], + }, + { + code: ` class A { constructor() { if (condition) {} // +1 } }`, - options: [0], - errors: [message(1, { line: 3, endLine: 3, column: 9, endColumn: 20 })], - }, - { - code: ` + options: [0], + errors: [message(1, { line: 3, endLine: 3, column: 9, endColumn: 20 })], + }, + { + code: ` class A { set foo(x) { if (condition) {} // +1 @@ -255,67 +256,67 @@ describe('S3776', () => { if (condition) {} // +1 } }`, - options: [0], - errors: [ - message(1, { line: 3, endLine: 3, column: 13, endColumn: 16 }), - message(1, { line: 6, endLine: 6, column: 13, endColumn: 16 }), - ], - }, - { - code: ` + options: [0], + errors: [ + message(1, { line: 3, endLine: 3, column: 13, endColumn: 16 }), + message(1, { line: 6, endLine: 6, column: 13, endColumn: 16 }), + ], + }, + { + code: ` class A { ['foo']() { if (condition) {} // +1 } }`, - options: [0], - errors: [message(1, { line: 3, endLine: 3, column: 10, endColumn: 15 })], - }, - { - // here function is a function declaration, but it has no name (despite of the @types/estree definition) - code: ` + options: [0], + errors: [message(1, { line: 3, endLine: 3, column: 10, endColumn: 15 })], + }, + { + // here function is a function declaration, but it has no name (despite of the @types/estree definition) + code: ` export default function() { if (options) {} }`, - options: [0], - errors: [message(1, { line: 2, endLine: 2, column: 22, endColumn: 30 })], - }, + options: [0], + errors: [message(1, { line: 2, endLine: 2, column: 22, endColumn: 30 })], + }, - // nested functions - { - code: ` + // nested functions + { + code: ` function nesting_func_no_complexity() { function nested_func() { // Noncompliant if (condition) {} // +1 } }`, - options: [0], - errors: [message(1, { line: 3 })], - }, - { - code: ` + options: [0], + errors: [message(1, { line: 3 })], + }, + { + code: ` function nesting_func_with_complexity() { // Noncompliant if (condition) {} // +1 function nested_func() { // Noncompliant if (condition) {} // +1 } }`, - options: [0], - errors: [message(1, { line: 2 }), message(1, { line: 4 })], - }, - { - code: ` + options: [0], + errors: [message(1, { line: 2 }), message(1, { line: 4 })], + }, + { + code: ` function nesting_func_with_not_structural_complexity() { // Noncompliant return a && b; // +1 function nested_func() { // Noncompliant if (condition) {} // +1 } }`, - options: [0], - errors: [message(1, { line: 2 }), message(1, { line: 4 })], - }, - { - code: ` + options: [0], + errors: [message(1, { line: 2 }), message(1, { line: 4 })], + }, + { + code: ` function two_level_function_nesting() { function nested1() { function nested2() { // Noncompliant @@ -323,11 +324,11 @@ describe('S3776', () => { } } }`, - options: [0], - errors: [message(1, { line: 4 })], - }, - { - code: ` + options: [0], + errors: [message(1, { line: 4 })], + }, + { + code: ` function two_level_function_nesting_2() { function nested1() { // Noncompliant if (condition) {} // +1 @@ -336,22 +337,22 @@ describe('S3776', () => { } } }`, - options: [0], - errors: [message(1, { line: 3 }), message(1, { line: 5 })], - }, - { - code: ` + options: [0], + errors: [message(1, { line: 3 }), message(1, { line: 5 })], + }, + { + code: ` function with_complexity_after_nested_function() { // Noncompliant function nested_func() { // Noncompliant if (condition) {} // +1 } if (condition) {} // +1 }`, - options: [0], - errors: [message(1, { line: 2 }), message(1, { line: 3 })], - }, - { - code: ` + options: [0], + errors: [message(1, { line: 2 }), message(1, { line: 3 })], + }, + { + code: ` function nested_async_method() { class X { async method() { @@ -359,24 +360,24 @@ describe('S3776', () => { } } }`, - options: [0], - errors: [message(1, { line: 4, column: 17, endColumn: 23 })], - }, + options: [0], + errors: [message(1, { line: 4, column: 17, endColumn: 23 })], + }, - // spaghetti - { - code: ` + // spaghetti + { + code: ` (function(a) { // Noncompliant if (cond) {} return a; })(function(b) {return b + 1})(0);`, - options: [0], - errors: [message(1)], - }, + options: [0], + errors: [message(1)], + }, - // ignore React functional components - { - code: ` + // ignore React functional components + { + code: ` function Welcome() { const handleSomething = () => { if (x) {} // +1 @@ -384,11 +385,11 @@ describe('S3776', () => { if (x) {} // +1 return

Hello, world

; }`, - options: [0], - errors: [message(1, { line: 2 }), message(1, { line: 3 })], - }, - { - code: ` + options: [0], + errors: [message(1, { line: 2 }), message(1, { line: 3 })], + }, + { + code: ` const Welcome = () => { const handleSomething = () => { if (x) {} // +1 @@ -396,11 +397,11 @@ describe('S3776', () => { if (x) {} // +1 return

Hello, world

; }`, - options: [0], - errors: [message(1, { line: 2 }), message(1, { line: 3 })], - }, - { - code: ` + options: [0], + errors: [message(1, { line: 2 }), message(1, { line: 3 })], + }, + { + code: ` const Welcome = () => { const handleSomething = () => { if (x) {} // +1 @@ -413,11 +414,11 @@ describe('S3776', () => { ); }`, - options: [0], - errors: [message(1, { line: 2 }), message(1, { line: 3 })], - }, - testCaseWithSonarRuntime( - ` + options: [0], + errors: [message(1, { line: 2 }), message(1, { line: 3 })], + }, + testCaseWithSonarRuntime( + ` function Component(obj) { return ( <> @@ -425,12 +426,12 @@ describe('S3776', () => { ); }`, - [ - { message: '+1', column: 56, line: 5, endColumn: 57, endLine: 5 }, // ?: - ], - ), - testCaseWithSonarRuntime( - ` + [ + { message: '+1', column: 56, line: 5, endColumn: 57, endLine: 5 }, // ?: + ], + ), + testCaseWithSonarRuntime( + ` function Component(obj) { return ( <> @@ -438,12 +439,12 @@ describe('S3776', () => { ); }`, - [ - { message: '+1', column: 25, line: 5, endColumn: 27, endLine: 5 }, // && - ], - ), - testCaseWithSonarRuntime( - ` + [ + { message: '+1', column: 25, line: 5, endColumn: 27, endLine: 5 }, // && + ], + ), + testCaseWithSonarRuntime( + ` function Component(obj) { return ( <> @@ -451,18 +452,18 @@ describe('S3776', () => { ); }`, - [ - { message: '+1', column: 25, line: 5, endColumn: 27, endLine: 5 }, // && - { message: '+1', column: 40, line: 5, endColumn: 41, endLine: 5 }, // || - ], - ), - ], - }); + [ + { message: '+1', column: 25, line: 5, endColumn: 27, endLine: 5 }, // && + { message: '+1', column: 40, line: 5, endColumn: 41, endLine: 5 }, // || + ], + ), + ], + }); - ruleTester.run('cognitive-complexity 15', rule, { - valid: [ - { - code: ` + ruleTester.run('cognitive-complexity 15', rule, { + valid: [ + { + code: ` function foo() { if (a) { // +1 (nesting level +1) if (b) { // +2 (nesting level +1) @@ -474,11 +475,11 @@ describe('S3776', () => { } } }`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function foo() { if (a) { // +1 (nesting level +1) if (b) { // +2 (nesting level +1) @@ -492,24 +493,24 @@ describe('S3776', () => { } } }`, - errors: [ - { - messageId: 'refactorFunction', - data: { - complexityAmount: 21, - threshold: 15, + errors: [ + { + messageId: 'refactorFunction', + data: { + complexityAmount: 21, + threshold: 15, + }, }, - }, - ], - }, - ], - }); + ], + }, + ], + }); - ruleTester.run('file-cognitive-complexity', rule, { - valid: [], - invalid: [ - { - code: ` + ruleTester.run('file-cognitive-complexity', rule, { + valid: [], + invalid: [ + { + code: ` a; // Noncompliant [[id=1]] {{25}} function foo() { x && y; @@ -589,40 +590,41 @@ class TopLevel { } } `, - options: [0, 'metric'], - errors: [{ messageId: 'fileComplexity', data: { complexityAmount: 25 } }], - }, - ], - }); - - function testCaseWithSonarRuntime( - code: string, - secondaryLocations: IssueLocation[], - complexity?: number, - ) { - const cost = complexity ?? secondaryLocations.length; - const message = `Refactor this function to reduce its Cognitive Complexity from ${cost} to the 0 allowed.`; - const sonarRuntimeData = JSON.stringify({ message, secondaryLocations, cost }); - return { - code, - options: [0, 'sonar-runtime'], - errors: [ - { - messageId: 'sonarRuntime', - data: { - threshold: 0, - sonarRuntimeData, - }, + options: [0, 'metric'], + errors: [{ messageId: 'fileComplexity', data: { complexityAmount: 25 } }], }, ], - }; - } + }); - function message(complexityAmount: number, other = {}) { - return { - messageId: 'refactorFunction', - data: { complexityAmount, threshold: 0 }, - ...other, - }; - } + function testCaseWithSonarRuntime( + code: string, + secondaryLocations: IssueLocation[], + complexity?: number, + ) { + const cost = complexity ?? secondaryLocations.length; + const message = `Refactor this function to reduce its Cognitive Complexity from ${cost} to the 0 allowed.`; + const sonarRuntimeData = JSON.stringify({ message, secondaryLocations, cost }); + return { + code, + options: [0, 'sonar-runtime'], + errors: [ + { + messageId: 'sonarRuntime', + data: { + threshold: 0, + sonarRuntimeData, + }, + }, + ], + }; + } + + function message(complexityAmount: number, other = {}) { + return { + messageId: 'refactorFunction', + data: { complexityAmount, threshold: 0 }, + ...other, + }; + } + }); }); diff --git a/packages/jsts/src/rules/S3782/unit.test.ts b/packages/jsts/src/rules/S3782/unit.test.ts index 67165c052f..194dc847af 100644 --- a/packages/jsts/src/rules/S3782/unit.test.ts +++ b/packages/jsts/src/rules/S3782/unit.test.ts @@ -16,147 +16,149 @@ */ import { rule } from './index.js'; import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3782', () => { - const eslintRuleTester = new DefaultParserRuleTester(); - eslintRuleTester.run('Correct types should be used [js]', rule, { - valid: [ - { - code: `Math.abs("42"); // not reported without type information`, - }, - ], - invalid: [], - }); + it('S3782', () => { + const eslintRuleTester = new DefaultParserRuleTester(); + eslintRuleTester.run('Correct types should be used [js]', rule, { + valid: [ + { + code: `Math.abs("42"); // not reported without type information`, + }, + ], + invalid: [], + }); - const typeScriptRuleTester = new RuleTester(); - typeScriptRuleTester.run('Correct types should be used', rule, { - valid: [ - { - code: ` + const typeScriptRuleTester = new RuleTester(); + typeScriptRuleTester.run('Correct types should be used', rule, { + valid: [ + { + code: ` var arr = []; arr.indexOf('x') === 7; `, - }, - { - code: ` + }, + { + code: ` var str = "str"; str.charAt(5); `, - }, - { - code: ` + }, + { + code: ` var str = "str"; str.charAt(unknown); `, - }, - { - code: ` + }, + { + code: ` var slice = [].slice; slice.call(arguments, 1); `, - }, - { - code: `Math.max(1, 2)`, - }, - { - code: ` + }, + { + code: `Math.max(1, 2)`, + }, + { + code: ` function upperToHyphenLower(match, offset, string) { return (offset > 0 ? '-' : '') + match.toLowerCase(); } "foo".replace('dog', upperToHyphenLower); `, - }, - { - code: ` + }, + { + code: ` var arr = [1, 2, 3]; var i = 0; arr.forEach(function (a) { i += 1; }); `, - }, - { - code: ` + }, + { + code: ` const regex = RegExp('foo*'); regex.test(false); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` var str = "str"; str.charAt("5"); `, - errors: [ - { - message: `Verify that argument is of correct type: expected 'number' instead of 'string'.`, - line: 3, - column: 18, - endLine: 3, - endColumn: 21, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Verify that argument is of correct type: expected 'number' instead of 'string'.`, + line: 3, + column: 18, + endLine: 3, + endColumn: 21, + }, + ], + }, + { + code: ` var str = "str"; str.charAt({x: "5"}); `, - errors: [ - { - message: `Verify that argument is of correct type: expected 'number' instead of '{ x: string; }'.`, - line: 3, - column: 18, - endLine: 3, - endColumn: 26, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Verify that argument is of correct type: expected 'number' instead of '{ x: string; }'.`, + line: 3, + column: 18, + endLine: 3, + endColumn: 26, + }, + ], + }, + { + code: ` Math.abs("42") `, - errors: [ - { - message: `Verify that argument is of correct type: expected 'number' instead of 'string'.`, - line: 2, - column: 16, - endLine: 2, - endColumn: 20, - }, - ], - }, - { - code: ` var x = []; + errors: [ + { + message: `Verify that argument is of correct type: expected 'number' instead of 'string'.`, + line: 2, + column: 16, + endLine: 2, + endColumn: 20, + }, + ], + }, + { + code: ` var x = []; x.slice(false); `, - errors: [ - { - message: - "Verify that argument is of correct type: expected 'number' instead of 'boolean'.", - line: 2, - column: 17, - endLine: 2, - endColumn: 22, - }, - ], - }, - { - code: ` + errors: [ + { + message: + "Verify that argument is of correct type: expected 'number' instead of 'boolean'.", + line: 2, + column: 17, + endLine: 2, + endColumn: 22, + }, + ], + }, + { + code: ` (5).toString("hex"); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` new Date().setTime("a"); `, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3785/unit.test.ts b/packages/jsts/src/rules/S3785/unit.test.ts index f136544df0..daf92b1d7b 100644 --- a/packages/jsts/src/rules/S3785/unit.test.ts +++ b/packages/jsts/src/rules/S3785/unit.test.ts @@ -16,62 +16,64 @@ */ import { rule } from './index.js'; import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3785', () => { - const ruleTesterJs = new DefaultParserRuleTester(); - ruleTesterJs.run('"in" should not be used with primitive types [js]', rule, { - valid: [ - { - code: `unknown in 1; // not reported without type information`, - }, - ], - invalid: [], - }); + it('S3785', () => { + const ruleTesterJs = new DefaultParserRuleTester(); + ruleTesterJs.run('"in" should not be used with primitive types [js]', rule, { + valid: [ + { + code: `unknown in 1; // not reported without type information`, + }, + ], + invalid: [], + }); - const ruleTesterTs = new RuleTester(); - ruleTesterTs.run(`"in" should not be used with primitive types [ts]`, rule, { - valid: [ - { - code: `1 in [1, 2, 3];`, - }, - { - code: `1 in new Number(1);`, - }, - { - code: `'prop' in { 'prop': 1 };`, - }, - ], - invalid: [ - { - code: `unknown in 1;`, - errors: [ - { - message: `{\"message\":\"TypeError can be thrown as this operand might have primitive type.\",\"secondaryLocations\":[{\"column\":8,\"line\":1,\"endColumn\":10,\"endLine\":1}]}`, - line: 1, - column: 12, - endLine: 1, - endColumn: 13, - }, - ], - options: ['sonar-runtime'], - }, - { - code: `unknown in 'str';`, - errors: 1, - }, - { - code: `unknown in true;`, - errors: 1, - }, - { - code: `unknown in null;`, - errors: 1, - }, - { - code: `unknown in undefined;`, - errors: 1, - }, - ], + const ruleTesterTs = new RuleTester(); + ruleTesterTs.run(`"in" should not be used with primitive types [ts]`, rule, { + valid: [ + { + code: `1 in [1, 2, 3];`, + }, + { + code: `1 in new Number(1);`, + }, + { + code: `'prop' in { 'prop': 1 };`, + }, + ], + invalid: [ + { + code: `unknown in 1;`, + errors: [ + { + message: `{\"message\":\"TypeError can be thrown as this operand might have primitive type.\",\"secondaryLocations\":[{\"column\":8,\"line\":1,\"endColumn\":10,\"endLine\":1}]}`, + line: 1, + column: 12, + endLine: 1, + endColumn: 13, + }, + ], + options: ['sonar-runtime'], + }, + { + code: `unknown in 'str';`, + errors: 1, + }, + { + code: `unknown in true;`, + errors: 1, + }, + { + code: `unknown in null;`, + errors: 1, + }, + { + code: `unknown in undefined;`, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3796/unit.test.ts b/packages/jsts/src/rules/S3796/unit.test.ts index 6dc59ab9b6..1188b4cb6b 100644 --- a/packages/jsts/src/rules/S3796/unit.test.ts +++ b/packages/jsts/src/rules/S3796/unit.test.ts @@ -16,39 +16,40 @@ */ import { rule } from './index.js'; import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3796', () => { - const typeScriptRuleTester = new RuleTester(); - typeScriptRuleTester.run( - 'Callbacks of array methods should have return statements [w types]', - rule, - { - valid: [ - { - code: ` + it('S3796', () => { + const typeScriptRuleTester = new RuleTester(); + typeScriptRuleTester.run( + 'Callbacks of array methods should have return statements [w types]', + rule, + { + valid: [ + { + code: ` const arr = []; arr.map(x => x*2)`, - }, - { - code: ` + }, + { + code: ` const obj = {}; obj.map(function () {})`, - }, - { - code: ` + }, + { + code: ` const arr = []; arr.forEach(function () {}); `, - }, - { - code: ` + }, + { + code: ` const arr = []; const mapper = someVar ? function () {} : function (x) {return x + 1}; arr.map(mapper)`, - }, - { - code: ` + }, + { + code: ` var myArray = [1, 2]; var result = myArray.map(async (element) => { await doSomething(element); }); @@ -59,48 +60,48 @@ describe('S3796', () => { var result = myArray.map(asyncFunc); var result = myArray.map(anotherAsyncFunc);`, - }, - { - code: ` + }, + { + code: ` Array.from(a); Array.from(a, b); Array.from(a, function(){return 42;}); Array.isArray(function(){}); Array.isArray(a, function(){});`, - }, - { - code: ` + }, + { + code: ` const arr = [] arr["foo"](function() {})`, - }, - { - code: ` + }, + { + code: ` function someFunc(callback) { callback(); } const arr = [someFunc]; const some = 0; arr[some](function() {console.log("hello there!")});`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const arr = []; arr.map(function(x) { x*2 })`, - errors: [ - { - message: `Add a "return" statement to this callback.`, - line: 3, - endLine: 3, - column: 15, - endColumn: 23, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Add a "return" statement to this callback.`, + line: 3, + endLine: 3, + column: 15, + endColumn: 23, + }, + ], + }, + { + code: ` const myArray = []; myArray.every(function(){}); // Noncompliant myArray.filter(function(){}); // Noncompliant @@ -112,25 +113,25 @@ describe('S3796', () => { myArray.some(function(){}); // Noncompliant myArray.sort(function(){}); // Noncompliant `, - errors: 9, - }, - { - code: ` + errors: 9, + }, + { + code: ` const arr = []; const mapper = function () {}; arr.map(mapper)`, - errors: [ - { - message: 'Add a "return" statement to this callback.', - line: 4, - endLine: 4, - column: 15, - endColumn: 21, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Add a "return" statement to this callback.', + line: 4, + endLine: 4, + column: 15, + endColumn: 21, + }, + ], + }, + { + code: ` var myArray = [1, 2]; var obj = { @@ -140,15 +141,15 @@ describe('S3796', () => { myArray.map(obj.goodCallback); myArray.map(obj.badCallback);`, - errors: [ - { - message: 'Add a "return" statement to this callback.', - line: 10, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Add a "return" statement to this callback.', + line: 10, + }, + ], + }, + { + code: ` var myArray = [1, 2]; var callbackProvider = function() { @@ -158,272 +159,273 @@ describe('S3796', () => { myArray.map(callbackProvider); // OK myArray.map(callbackProvider());`, - errors: [ - { - message: 'Add a "return" statement to this callback.', - line: 10, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Add a "return" statement to this callback.', + line: 10, + }, + ], + }, + { + code: ` Array.from(a, () => {}); // Noncompliant`, - errors: [ - { - message: 'Add a "return" statement to this callback.', - line: 2, - endLine: 2, - column: 24, - endColumn: 26, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Add a "return" statement to this callback.', + line: 2, + endLine: 2, + column: 24, + endColumn: 26, + }, + ], + }, + { + code: ` var myArray = [1, 2]; myArray.findLast(x => {}); // Noncompliant`, - errors: [ - { - message: 'Add a "return" statement to this callback.', - line: 3, - endLine: 3, - column: 26, - endColumn: 28, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Add a "return" statement to this callback.', + line: 3, + endLine: 3, + column: 26, + endColumn: 28, + }, + ], + }, + { + code: ` var myArray = [1, 2]; myArray.findLastIndex(x => {}); // Noncompliant`, - errors: [ - { - message: 'Add a "return" statement to this callback.', - line: 3, - endLine: 3, - column: 31, - endColumn: 33, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Add a "return" statement to this callback.', + line: 3, + endLine: 3, + column: 31, + endColumn: 33, + }, + ], + }, + { + code: ` var myArray = [1, 2]; myArray.toSorted(x => {}); // Noncompliant`, - errors: [ - { - message: 'Add a "return" statement to this callback.', - line: 3, - endLine: 3, - column: 26, - endColumn: 28, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Add a "return" statement to this callback.', + line: 3, + endLine: 3, + column: 26, + endColumn: 28, + }, + ], + }, + { + code: ` var myArray = [1, 2]; myArray.flatMap(x => {}); // Noncompliant`, - errors: [ - { - message: 'Add a "return" statement to this callback.', - line: 3, - endLine: 3, - column: 25, - endColumn: 27, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Add a "return" statement to this callback.', + line: 3, + endLine: 3, + column: 25, + endColumn: 27, + }, + ], + }, + { + code: ` var myArray = new Int8Array([1, 2]); myArray.every(x => {}); // Noncompliant`, - errors: [ - { - message: 'Add a "return" statement to this callback.', - line: 3, - endLine: 3, - column: 23, - endColumn: 25, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Add a "return" statement to this callback.', + line: 3, + endLine: 3, + column: 23, + endColumn: 25, + }, + ], + }, + { + code: ` var myArray = new Uint8Array([1, 2]); myArray.every(x => {}); // Noncompliant`, - errors: [ - { - message: 'Add a "return" statement to this callback.', - line: 3, - endLine: 3, - column: 23, - endColumn: 25, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Add a "return" statement to this callback.', + line: 3, + endLine: 3, + column: 23, + endColumn: 25, + }, + ], + }, + { + code: ` var myArray = new Uint8ClampedArray([1, 2]); myArray.every(x => {}); // Noncompliant`, - errors: [ - { - message: 'Add a "return" statement to this callback.', - line: 3, - endLine: 3, - column: 23, - endColumn: 25, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Add a "return" statement to this callback.', + line: 3, + endLine: 3, + column: 23, + endColumn: 25, + }, + ], + }, + { + code: ` var myArray = new Int16Array([1, 2]); myArray.every(x => {}); // Noncompliant`, - errors: [ - { - message: 'Add a "return" statement to this callback.', - line: 3, - endLine: 3, - column: 23, - endColumn: 25, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Add a "return" statement to this callback.', + line: 3, + endLine: 3, + column: 23, + endColumn: 25, + }, + ], + }, + { + code: ` var myArray = new Uint16Array([1, 2]); myArray.every(x => {}); // Noncompliant`, - errors: [ - { - message: 'Add a "return" statement to this callback.', - line: 3, - endLine: 3, - column: 23, - endColumn: 25, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Add a "return" statement to this callback.', + line: 3, + endLine: 3, + column: 23, + endColumn: 25, + }, + ], + }, + { + code: ` var myArray = new Int32Array([1, 2]); myArray.every(x => {}); // Noncompliant`, - errors: [ - { - message: 'Add a "return" statement to this callback.', - line: 3, - endLine: 3, - column: 23, - endColumn: 25, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Add a "return" statement to this callback.', + line: 3, + endLine: 3, + column: 23, + endColumn: 25, + }, + ], + }, + { + code: ` var myArray = new Uint32Array([1, 2]); myArray.every(x => {}); // Noncompliant`, - errors: [ - { - message: 'Add a "return" statement to this callback.', - line: 3, - endLine: 3, - column: 23, - endColumn: 25, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Add a "return" statement to this callback.', + line: 3, + endLine: 3, + column: 23, + endColumn: 25, + }, + ], + }, + { + code: ` var myArray = new Float32Array([1, 2]); myArray.every(x => {}); // Noncompliant`, - errors: [ - { - message: 'Add a "return" statement to this callback.', - line: 3, - endLine: 3, - column: 23, - endColumn: 25, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Add a "return" statement to this callback.', + line: 3, + endLine: 3, + column: 23, + endColumn: 25, + }, + ], + }, + { + code: ` var myArray = new Float64Array([1, 2]); myArray.every(x => {}); // Noncompliant`, - errors: [ - { - message: 'Add a "return" statement to this callback.', - line: 3, - endLine: 3, - column: 23, - endColumn: 25, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Add a "return" statement to this callback.', + line: 3, + endLine: 3, + column: 23, + endColumn: 25, + }, + ], + }, + { + code: ` var myArray = new BigInt64Array([1n, 2n]); myArray.every(x => {}); // Noncompliant`, - errors: [ - { - message: 'Add a "return" statement to this callback.', - line: 3, - endLine: 3, - column: 23, - endColumn: 25, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Add a "return" statement to this callback.', + line: 3, + endLine: 3, + column: 23, + endColumn: 25, + }, + ], + }, + { + code: ` var myArray = new BigUint64Array([1n, 2n]); myArray.every(x => {}); // Noncompliant`, - errors: [ - { - message: 'Add a "return" statement to this callback.', - line: 3, - endLine: 3, - column: 23, - endColumn: 25, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Add a "return" statement to this callback.', + line: 3, + endLine: 3, + column: 23, + endColumn: 25, + }, + ], + }, + { + code: ` var myArray = [1, 2]; myArray["every"](x => {}); // Noncompliant`, - errors: [ - { - message: 'Add a "return" statement to this callback.', - line: 3, - endLine: 3, - column: 26, - endColumn: 28, - }, - ], - }, - ], - }, - ); + errors: [ + { + message: 'Add a "return" statement to this callback.', + line: 3, + endLine: 3, + column: 26, + endColumn: 28, + }, + ], + }, + ], + }, + ); - const eslintRuleTester = new DefaultParserRuleTester(); - eslintRuleTester.run( - 'Callbacks of array methods should have return statements [w/o types]', - rule, - { - valid: [ - { - code: ` + const eslintRuleTester = new DefaultParserRuleTester(); + eslintRuleTester.run( + 'Callbacks of array methods should have return statements [w/o types]', + rule, + { + valid: [ + { + code: ` let arr = []; arr.map(x => x + 1);`, - }, - { - code: ` + }, + { + code: ` let arr = []; arr.map(x => { x + 1;})`, // issue not raised because no types are available - }, - ], - invalid: [], - }, - ); + }, + ], + invalid: [], + }, + ); + }); }); diff --git a/packages/jsts/src/rules/S3798/unit.test.ts b/packages/jsts/src/rules/S3798/unit.test.ts index 008d4923b8..6c00a56689 100644 --- a/packages/jsts/src/rules/S3798/unit.test.ts +++ b/packages/jsts/src/rules/S3798/unit.test.ts @@ -20,26 +20,26 @@ import { NoTypeCheckingRuleTester, } from '../../../tests/tools/testers/rule-tester.js'; import globals from 'globals'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3798', () => { - const ruleTester = new NoTypeCheckingRuleTester(); - const ruleTesterwithBrowser = new DefaultParserRuleTester({ - globals: { - ...globals.browser, - }, - }); - const ruleTesterCustomGlobals = new DefaultParserRuleTester({ - globals: { - angular: true, - other: true, - }, - }); - const ruleTesterScript = new DefaultParserRuleTester({ - sourceType: 'script', - }); + it('S3798', () => { + const ruleTester = new NoTypeCheckingRuleTester(); + const ruleTesterwithBrowser = new DefaultParserRuleTester({ + globals: { + ...globals.browser, + }, + }); + const ruleTesterCustomGlobals = new DefaultParserRuleTester({ + globals: { + angular: true, + other: true, + }, + }); + const ruleTesterScript = new DefaultParserRuleTester({ + sourceType: 'script', + }); - describe('S3798', () => { ruleTester.run('Variables and functions should not be declared in the global scope', rule, { valid: [ { diff --git a/packages/jsts/src/rules/S3800/unit.test.ts b/packages/jsts/src/rules/S3800/unit.test.ts index ce62363ea8..d7d7c4f2db 100644 --- a/packages/jsts/src/rules/S3800/unit.test.ts +++ b/packages/jsts/src/rules/S3800/unit.test.ts @@ -16,38 +16,39 @@ */ import { rule } from './index.js'; import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3800', () => { - const ruleTesterJs = new DefaultParserRuleTester(); - ruleTesterJs.run('Functions should always return the same type [js]', rule, { - valid: [ - { - code: ` + it('S3800', () => { + const ruleTesterJs = new DefaultParserRuleTester(); + ruleTesterJs.run('Functions should always return the same type [js]', rule, { + valid: [ + { + code: ` function foo() { if (condition) { return 42; } return 'str'; // not raised without type information }`, - }, - ], - invalid: [], - }); + }, + ], + invalid: [], + }); - const ruleTesterTs = new RuleTester(); - ruleTesterTs.run(`Functions should always return the same type [ts]`, rule, { - valid: [ - { - code: `return;`, - }, - { - code: ` + const ruleTesterTs = new RuleTester(); + ruleTesterTs.run(`Functions should always return the same type [ts]`, rule, { + valid: [ + { + code: `return;`, + }, + { + code: ` function foo() { }`, - }, - { - code: ` + }, + { + code: ` function foo() { if (condition) { return 42; @@ -55,17 +56,17 @@ describe('S3800', () => { return; } }`, - }, - { - code: ` + }, + { + code: ` function foo() { if (condition) { return 42; } }`, - }, - { - code: ` + }, + { + code: ` function foo() { if (condition) { return 42; @@ -73,9 +74,9 @@ describe('S3800', () => { return 24; } }`, - }, - { - code: ` + }, + { + code: ` function foo() { if (condition) { return 'hello'; @@ -83,9 +84,9 @@ describe('S3800', () => { return 'world'; } }`, - }, - { - code: ` + }, + { + code: ` function foo() { if (condition) { return true; @@ -93,9 +94,9 @@ describe('S3800', () => { return false; } }`, - }, - { - code: ` + }, + { + code: ` function foo() { if (condition) { return { num: 42 }; @@ -103,9 +104,9 @@ describe('S3800', () => { return { str: 'hello' }; } }`, - }, - { - code: ` + }, + { + code: ` function foo() { if (condition) { return [1, 2, 3]; @@ -113,9 +114,9 @@ describe('S3800', () => { return [4, 5, 6]; } }`, - }, - { - code: ` + }, + { + code: ` function foo() { if (condition) { return function (){}; @@ -123,9 +124,9 @@ describe('S3800', () => { return function (){}; } }`, - }, - { - code: ` + }, + { + code: ` function foo() { if (condition) { return new Date(); @@ -133,9 +134,9 @@ describe('S3800', () => { return new Date(); } }`, - }, - { - code: ` + }, + { + code: ` function foo() { if (condition1) { return 42; @@ -145,9 +146,9 @@ describe('S3800', () => { return undefined; } }`, - }, - { - code: ` + }, + { + code: ` function foo() { if (condition) { return 42; @@ -155,9 +156,9 @@ describe('S3800', () => { return any(); } }`, - }, - { - code: ` + }, + { + code: ` class A {} class B extends A {} function Factory() { @@ -167,9 +168,9 @@ describe('S3800', () => { return new B(); } }`, - }, - { - code: ` + }, + { + code: ` class A {} class B {} function Factory() { @@ -179,9 +180,9 @@ describe('S3800', () => { return new B(); } }`, - }, - { - code: ` + }, + { + code: ` /** @returns {(number|string)} - a union of number and string */ function foo() { if (condition) { @@ -189,9 +190,9 @@ describe('S3800', () => { } return 'str'; }`, - }, - { - code: ` + }, + { + code: ` function bar() {} function foo() { if (condition) { @@ -201,16 +202,16 @@ describe('S3800', () => { } } `, - }, - { - code: ` + }, + { + code: ` function foo(value: any): Object | Array { return value; } `, - }, - { - code: ` + }, + { + code: ` function createTypedArrayFactory(type, len) { if (type === 'float32') { return new Float32Array(len); @@ -224,9 +225,9 @@ describe('S3800', () => { return Array.from(Array(len)); } `, - }, - { - code: ` + }, + { + code: ` function foo() { if (condition) { return [1, 2, 3]; @@ -234,22 +235,22 @@ describe('S3800', () => { return ['foo', 'bar', 'baz']; } }`, - }, - { - code: ` + }, + { + code: ` function foo() { return condition ? 'str' : true; }`, - }, - { - code: ` + }, + { + code: ` const sanitize = () => { return condition ? true : 'Value should be a string'; }; `, - }, - { - code: ` + }, + { + code: ` const sanitize = () => { if (condition) { return true; @@ -257,11 +258,11 @@ const sanitize = () => { return 'Value should be a string'; }`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function foo() { let ret; if (condition) { @@ -271,92 +272,92 @@ const sanitize = () => { } return ret // FN - does not infer ret to number | string; }`, - errors: [ - { - message: 'Refactor this function to always return the same type.', - line: 2, - column: 18, - endLine: 2, - endColumn: 21, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Refactor this function to always return the same type.', + line: 2, + column: 18, + endLine: 2, + endColumn: 21, + }, + ], + }, + { + code: ` function foo() { if (condition) { return 42; } return 'str'; }`, - errors: [ - { - message: JSON.stringify({ - message: `Refactor this function to always return the same type.`, - secondaryLocations: [ - { - message: `Returns number`, - column: 12, - line: 4, - endColumn: 22, - endLine: 4, - }, - { - message: `Returns string`, - column: 10, - line: 6, - endColumn: 23, - endLine: 6, - }, - ], - }), - line: 2, - column: 18, - endLine: 2, - endColumn: 21, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `Refactor this function to always return the same type.`, + secondaryLocations: [ + { + message: `Returns number`, + column: 12, + line: 4, + endColumn: 22, + endLine: 4, + }, + { + message: `Returns string`, + column: 10, + line: 6, + endColumn: 23, + endLine: 6, + }, + ], + }), + line: 2, + column: 18, + endLine: 2, + endColumn: 21, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` function foo() { if (condition) { return 42; } return { foo: 'bar' }; }`, - errors: [ - { - message: JSON.stringify({ - message: `Refactor this function to always return the same type.`, - secondaryLocations: [ - { - message: `Returns number`, - column: 12, - line: 4, - endColumn: 22, - endLine: 4, - }, - { - message: `Returns object`, - column: 10, - line: 6, - endColumn: 32, - endLine: 6, - }, - ], - }), - line: 2, - column: 18, - endLine: 2, - endColumn: 21, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `Refactor this function to always return the same type.`, + secondaryLocations: [ + { + message: `Returns number`, + column: 12, + line: 4, + endColumn: 22, + endLine: 4, + }, + { + message: `Returns object`, + column: 10, + line: 6, + endColumn: 32, + endLine: 6, + }, + ], + }), + line: 2, + column: 18, + endLine: 2, + endColumn: 21, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` function foo() { if (condition1) { return; @@ -370,37 +371,37 @@ const sanitize = () => { return 'str'; } }`, - errors: [ - { - message: JSON.stringify({ - message: `Refactor this function to always return the same type.`, - secondaryLocations: [ - { - message: `Returns number`, - column: 12, - line: 10, - endColumn: 22, - endLine: 10, - }, - { - message: `Returns string`, - column: 12, - line: 12, - endColumn: 25, - endLine: 12, - }, - ], - }), - line: 2, - column: 18, - endLine: 2, - endColumn: 21, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `Refactor this function to always return the same type.`, + secondaryLocations: [ + { + message: `Returns number`, + column: 12, + line: 10, + endColumn: 22, + endLine: 10, + }, + { + message: `Returns string`, + column: 12, + line: 12, + endColumn: 25, + endLine: 12, + }, + ], + }), + line: 2, + column: 18, + endLine: 2, + endColumn: 21, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` function fn() { return 'str'; } function foo() { if (condition) { @@ -409,37 +410,37 @@ const sanitize = () => { return fn; } }`, - errors: [ - { - message: JSON.stringify({ - message: `Refactor this function to always return the same type.`, - secondaryLocations: [ - { - message: `Returns number`, - column: 12, - line: 5, - endColumn: 22, - endLine: 5, - }, - { - message: `Returns function`, - column: 12, - line: 7, - endColumn: 22, - endLine: 7, - }, - ], - }), - line: 3, - column: 18, - endLine: 3, - endColumn: 21, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `Refactor this function to always return the same type.`, + secondaryLocations: [ + { + message: `Returns number`, + column: 12, + line: 5, + endColumn: 22, + endLine: 5, + }, + { + message: `Returns function`, + column: 12, + line: 7, + endColumn: 22, + endLine: 7, + }, + ], + }), + line: 3, + column: 18, + endLine: 3, + endColumn: 21, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` function foo() { if (condition1) { return 42; @@ -453,58 +454,58 @@ const sanitize = () => { return [ { foo: 'bar' } ]; } }`, - errors: [ - { - message: JSON.stringify({ - message: `Refactor this function to always return the same type.`, - secondaryLocations: [ - { - message: `Returns number`, - column: 12, - line: 4, - endColumn: 22, - endLine: 4, - }, - { - message: `Returns array`, - column: 12, - line: 6, - endColumn: 26, - endLine: 6, - }, - { - message: `Returns array`, - column: 12, - line: 8, - endColumn: 29, - endLine: 8, - }, - { - message: `Returns array`, - column: 12, - line: 10, - endColumn: 28, - endLine: 10, - }, - { - message: `Returns array`, - column: 12, - line: 12, - endColumn: 38, - endLine: 12, - }, - ], - }), - line: 2, - column: 18, - endLine: 2, - endColumn: 21, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `Refactor this function to always return the same type.`, + secondaryLocations: [ + { + message: `Returns number`, + column: 12, + line: 4, + endColumn: 22, + endLine: 4, + }, + { + message: `Returns array`, + column: 12, + line: 6, + endColumn: 26, + endLine: 6, + }, + { + message: `Returns array`, + column: 12, + line: 8, + endColumn: 29, + endLine: 8, + }, + { + message: `Returns array`, + column: 12, + line: 10, + endColumn: 28, + endLine: 10, + }, + { + message: `Returns array`, + column: 12, + line: 12, + endColumn: 38, + endLine: 12, + }, + ], + }), + line: 2, + column: 18, + endLine: 2, + endColumn: 21, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` class C { m() { if (condition) { @@ -514,10 +515,10 @@ const sanitize = () => { } } }`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` /** @param {(number|string)} - a union of number and string */ function foo() { if (condition) { @@ -525,63 +526,63 @@ const sanitize = () => { } return 'str'; }`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` (function () { if (condition) { return 42; } return 'str'; })`, - errors: [ - { - message: 'Refactor this function to always return the same type.', - line: 2, - column: 10, - endLine: 2, - endColumn: 18, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Refactor this function to always return the same type.', + line: 2, + column: 10, + endLine: 2, + endColumn: 18, + }, + ], + }, + { + code: ` () => { if (condition) { return 42; } return 'str'; }`, - errors: [ - { - message: 'Refactor this function to always return the same type.', - line: 2, - column: 12, - endLine: 2, - endColumn: 14, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Refactor this function to always return the same type.', + line: 2, + column: 12, + endLine: 2, + endColumn: 14, + }, + ], + }, + { + code: ` const sanitize = () => { return condition ? true : 42; }; `, - errors: 1, - }, - ], - }); + errors: 1, + }, + ], + }); - const ruleTestJSWithTypes = new RuleTester(); - ruleTestJSWithTypes.run( - `'Functions should always return the same type [js with type inference]'`, - rule, - { - valid: [ - { - code: ` + const ruleTestJSWithTypes = new RuleTester(); + ruleTestJSWithTypes.run( + `'Functions should always return the same type [js with type inference]'`, + rule, + { + valid: [ + { + code: ` /** * @param {Function|Object} supplier The object or function supplying the properties to be mixed. */ @@ -592,9 +593,10 @@ const sanitize = () => { }, }); `, - }, - ], - invalid: [], - }, - ); + }, + ], + invalid: [], + }, + ); + }); }); diff --git a/packages/jsts/src/rules/S3801/unit.test.ts b/packages/jsts/src/rules/S3801/unit.test.ts index 9e7cae9655..e1d9db24df 100644 --- a/packages/jsts/src/rules/S3801/unit.test.ts +++ b/packages/jsts/src/rules/S3801/unit.test.ts @@ -16,15 +16,16 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3801', () => { - const ruleTester = new RuleTester(); + it('S3801', () => { + const ruleTester = new RuleTester(); - ruleTester.run(`Functions should use "return" consistently`, rule, { - valid: [ - { - code: ` + ruleTester.run(`Functions should use "return" consistently`, rule, { + valid: [ + { + code: ` function empty() { } @@ -136,18 +137,18 @@ describe('S3801', () => { var simple_arrow_function = (a) => 42; var arrowWithExpressionBody = (p) => p ? true : false;`, - }, - { - code: ` + }, + { + code: ` function withNeverType(a) { if (a === 1) { return true; } throw new Error('False') }`, - }, - { - code: ` + }, + { + code: ` function throwError(message: string): never { throw new Error(message); } @@ -158,63 +159,63 @@ describe('S3801', () => { throwError('False') } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` export function inconsistent(p: boolean) { if (p) { return true; } }`, - errors: [ - { - message: - '{"message":"Refactor this function to use \\"return\\" consistently.","secondaryLocations":[{"message":"Return with value","column":12,"line":4,"endColumn":24,"endLine":4},{"message":"Implicit return without value","column":8,"line":6,"endColumn":9,"endLine":6}]}', - line: 2, - endLine: 2, - column: 25, - endColumn: 37, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: + '{"message":"Refactor this function to use \\"return\\" consistently.","secondaryLocations":[{"message":"Return with value","column":12,"line":4,"endColumn":24,"endLine":4},{"message":"Implicit return without value","column":8,"line":6,"endColumn":9,"endLine":6}]}', + line: 2, + endLine: 2, + column: 25, + endColumn: 37, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` var function_expression = function () { if (condition) { return 42; } }`, - errors: [ - { - message: - '{"message":"Refactor this function to use \\"return\\" consistently.","secondaryLocations":[{"message":"Return with value","column":12,"line":4,"endColumn":22,"endLine":4},{"message":"Implicit return without value","column":8,"line":6,"endColumn":9,"endLine":6}]}', - line: 2, - endLine: 2, - column: 35, - endColumn: 43, - }, - ], - options: ['sonar-runtime'], - }, - { - code: `var inconsistentArrow = (p) => {if (p) { return true; } return; };`, - errors: [ - { - message: - '{"message":"Refactor this function to use \\"return\\" consistently.","secondaryLocations":[{"message":"Return with value","column":41,"line":1,"endColumn":53,"endLine":1},{"message":"Return without value","column":56,"line":1,"endColumn":63,"endLine":1}]}', - line: 1, - endLine: 1, - column: 29, - endColumn: 31, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: + '{"message":"Refactor this function to use \\"return\\" consistently.","secondaryLocations":[{"message":"Return with value","column":12,"line":4,"endColumn":22,"endLine":4},{"message":"Implicit return without value","column":8,"line":6,"endColumn":9,"endLine":6}]}', + line: 2, + endLine: 2, + column: 35, + endColumn: 43, + }, + ], + options: ['sonar-runtime'], + }, + { + code: `var inconsistentArrow = (p) => {if (p) { return true; } return; };`, + errors: [ + { + message: + '{"message":"Refactor this function to use \\"return\\" consistently.","secondaryLocations":[{"message":"Return with value","column":41,"line":1,"endColumn":53,"endLine":1},{"message":"Return without value","column":56,"line":1,"endColumn":63,"endLine":1}]}', + line: 1, + endLine: 1, + column: 29, + endColumn: 31, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` function* inconsistentGenerator(p) { let i = 0 while(i < 10) { @@ -224,20 +225,20 @@ describe('S3801', () => { return true; } }`, - errors: [ - { - message: - '{"message":"Refactor this function to use \\"return\\" consistently.","secondaryLocations":[{"message":"Return with value","column":12,"line":8,"endColumn":24,"endLine":8},{"message":"Implicit return without value","column":8,"line":10,"endColumn":9,"endLine":10}]}', - line: 2, - endLine: 2, - column: 19, - endColumn: 40, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: + '{"message":"Refactor this function to use \\"return\\" consistently.","secondaryLocations":[{"message":"Return with value","column":12,"line":8,"endColumn":24,"endLine":8},{"message":"Implicit return without value","column":8,"line":10,"endColumn":9,"endLine":10}]}', + line: 2, + endLine: 2, + column: 19, + endColumn: 40, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` function inconsistentNestedFunctions() { return true; @@ -247,20 +248,20 @@ describe('S3801', () => { } } }`, - errors: [ - { - message: - '{"message":"Refactor this function to use \\"return\\" consistently.","secondaryLocations":[{"message":"Return with value","column":14,"line":7,"endColumn":26,"endLine":7},{"message":"Implicit return without value","column":10,"line":9,"endColumn":11,"endLine":9}]}', - line: 5, - endLine: 5, - column: 20, - endColumn: 23, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: + '{"message":"Refactor this function to use \\"return\\" consistently.","secondaryLocations":[{"message":"Return with value","column":14,"line":7,"endColumn":26,"endLine":7},{"message":"Implicit return without value","column":10,"line":9,"endColumn":11,"endLine":9}]}', + line: 5, + endLine: 5, + column: 20, + endColumn: 23, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` class A { inconsistentMethod(p) { if (p) { @@ -285,10 +286,10 @@ describe('S3801', () => { } } }`, - errors: 3, - }, - { - code: ` + errors: 3, + }, + { + code: ` const myObj = { propertyAsFunction() { if (this._value) { @@ -296,11 +297,11 @@ describe('S3801', () => { } } }`, - errors: 1, - }, - // possible FP, see https://github.com/SonarSource/SonarJS/issues/2579 - { - code: ` + errors: 1, + }, + // possible FP, see https://github.com/SonarSource/SonarJS/issues/2579 + { + code: ` function throwError(message: string): never { throw new Error(message); } @@ -311,8 +312,9 @@ describe('S3801', () => { throwError('False') } `, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3827/unit.test.ts b/packages/jsts/src/rules/S3827/unit.test.ts index 83b76275d8..51388da21f 100644 --- a/packages/jsts/src/rules/S3827/unit.test.ts +++ b/packages/jsts/src/rules/S3827/unit.test.ts @@ -16,89 +16,90 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3827', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Variables should be defined before being used', rule, { - valid: [ - { - code: ` + it('S3827', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Variables should be defined before being used', rule, { + valid: [ + { + code: ` function foo() {} var a1; foo(a1); `, - }, - { - code: ` + }, + { + code: ` function foo() {} foo(a2); var a2; `, - }, - { - code: ` + }, + { + code: ` function foo() {} a3 = ""; foo(a3); foo(a3.xxx); `, - }, - { - code: ` + }, + { + code: ` {xxx: "property value"}; `, - }, - { - code: ` + }, + { + code: ` typeof x3; `, - }, - { - code: ` + }, + { + code: ` function foo() {} if (typeof x5 !== undefined) { foo(x5); } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function foo() {} foo(x1); `, - errors: [ - { - message: JSON.stringify({ - message: - '"x1" does not exist. Change its name or declare it so that its usage doesn\'t result in a "ReferenceError".', - secondaryLocations: [], - }), - line: 3, - endLine: 3, - column: 11, - endColumn: 13, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: + '"x1" does not exist. Change its name or declare it so that its usage doesn\'t result in a "ReferenceError".', + secondaryLocations: [], + }), + line: 3, + endLine: 3, + column: 11, + endColumn: 13, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` var a1 = 1; a1 + x2; `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` typeof x4.x; `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` function foo() {} foo(let1); if (true) { @@ -107,47 +108,48 @@ describe('S3827', () => { } foo(let1); `, - errors: [ - { - message: JSON.stringify({ - message: - '"let1" does not exist. Change its name or declare it so that its usage doesn\'t result in a "ReferenceError".', - secondaryLocations: [{ column: 10, line: 8, endColumn: 14, endLine: 8 }], - }), - line: 3, - endLine: 3, - column: 11, - endColumn: 15, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: + '"let1" does not exist. Change its name or declare it so that its usage doesn\'t result in a "ReferenceError".', + secondaryLocations: [{ column: 10, line: 8, endColumn: 14, endLine: 8 }], + }), + line: 3, + endLine: 3, + column: 11, + endColumn: 15, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` foo(let2); let let2 = 1; `, - errors: 1, - }, - { - // even if we report on `_` in unit test here, in real analysis it should not happen as `_` is set as a default global - code: `_.foo();`, - errors: 1, - }, - ], - }); + errors: 1, + }, + { + // even if we report on `_` in unit test here, in real analysis it should not happen as `_` is set as a default global + code: `_.foo();`, + errors: 1, + }, + ], + }); - const ruleTesterScript = new RuleTester(); - ruleTesterScript.run('No issues within with statements', rule, { - valid: [ - { - code: ` + const ruleTesterScript = new RuleTester(); + ruleTesterScript.run('No issues within with statements', rule, { + valid: [ + { + code: ` with (something) { foo(bar); } `, - }, - ], - invalid: [], + }, + ], + invalid: [], + }); }); }); diff --git a/packages/jsts/src/rules/S3854/unit.test.ts b/packages/jsts/src/rules/S3854/unit.test.ts index 41273a1253..e94350b921 100644 --- a/packages/jsts/src/rules/S3854/unit.test.ts +++ b/packages/jsts/src/rules/S3854/unit.test.ts @@ -16,14 +16,15 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3854', () => { - const ruleTester = new RuleTester(); - ruleTester.run('"super()" should be invoked appropriately', rule, { - valid: [ - { - code: ` + it('S3854', () => { + const ruleTester = new RuleTester(); + ruleTester.run('"super()" should be invoked appropriately', rule, { + valid: [ + { + code: ` var B1b = class extends A1 { constructor() { super(); // OK @@ -31,17 +32,18 @@ describe('S3854', () => { } } `, - }, - ], - invalid: [ - { - code: `class A extends B { constructor() {this.bar();}}`, - errors: 2, - }, - { - code: `class A extends B { constructor(a) { while (a) super(); } }`, - errors: 2, - }, - ], + }, + ], + invalid: [ + { + code: `class A extends B { constructor() {this.bar();}}`, + errors: 2, + }, + { + code: `class A extends B { constructor(a) { while (a) super(); } }`, + errors: 2, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3923/unit.test.ts b/packages/jsts/src/rules/S3923/unit.test.ts index 18d794a940..66d261a169 100644 --- a/packages/jsts/src/rules/S3923/unit.test.ts +++ b/packages/jsts/src/rules/S3923/unit.test.ts @@ -16,28 +16,29 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3923', () => { - const ruleTester = new RuleTester(); + it('S3923', () => { + const ruleTester = new RuleTester(); - ruleTester.run('S3923 if', rule, { - valid: [ - { code: "if (a) { first('const'); } else { first('var'); }" }, - { code: 'if (a) { first(); } else { second(); }' }, - { code: 'if (a) { first(); } else if (b) { first(); }' }, // ok, no `else` - { code: 'if (a) { first(); } else if (b) { second(); }' }, - { code: 'if (a) { second(); } else if (b) { first(); } else { first(); }' }, - { code: 'if (a) { first(); } else if (b) { second(); } else { first(); }' }, - { code: 'if (a) { first(); } else if (b) { first(); } else { second(); }' }, - { code: 'if (a) { first(); second(); } else { second(); first(); }' }, - { code: 'if (a) { first(); second(); } else { first(); third(); }' }, - { code: 'if (a) { first(); second(); } else { first(); }' }, - { - code: 'if (a) { first(); second(); } else if (b) { first(); second(); } else { first(); third(); }', - }, - { - code: ` + ruleTester.run('S3923 if', rule, { + valid: [ + { code: "if (a) { first('const'); } else { first('var'); }" }, + { code: 'if (a) { first(); } else { second(); }' }, + { code: 'if (a) { first(); } else if (b) { first(); }' }, // ok, no `else` + { code: 'if (a) { first(); } else if (b) { second(); }' }, + { code: 'if (a) { second(); } else if (b) { first(); } else { first(); }' }, + { code: 'if (a) { first(); } else if (b) { second(); } else { first(); }' }, + { code: 'if (a) { first(); } else if (b) { first(); } else { second(); }' }, + { code: 'if (a) { first(); second(); } else { second(); first(); }' }, + { code: 'if (a) { first(); second(); } else { first(); third(); }' }, + { code: 'if (a) { first(); second(); } else { first(); }' }, + { + code: 'if (a) { first(); second(); } else if (b) { first(); second(); } else { first(); third(); }', + }, + { + code: ` function render() { if (a) { return

foo

; @@ -45,61 +46,61 @@ describe('S3923', () => { return

bar

; } }`, - }, - ], - invalid: [ - { - code: 'if (a) { first(); } else { first(); }', - errors: [ - { - messageId: 'removeOrEditConditionalStructure', - line: 1, - column: 1, - endColumn: 38, - }, - ], - }, - { - code: 'if (a) { first(); } else if (b) { first(); } else { first(); }', - errors: [ - { - messageId: 'removeOrEditConditionalStructure', - line: 1, - column: 1, - endColumn: 63, - }, - ], - }, - { - code: 'if (a) { first(); second(); } else { first(); second(); }', - errors: [ - { - messageId: 'removeOrEditConditionalStructure', - line: 1, - column: 1, - endColumn: 58, - }, - ], - }, - { - code: 'if (a) { first(); second(); } else if (b) { first(); second(); } else { first(); second(); }', - errors: [ - { - messageId: 'removeOrEditConditionalStructure', - line: 1, - column: 1, - endColumn: 93, - }, - ], - }, - ], - }); + }, + ], + invalid: [ + { + code: 'if (a) { first(); } else { first(); }', + errors: [ + { + messageId: 'removeOrEditConditionalStructure', + line: 1, + column: 1, + endColumn: 38, + }, + ], + }, + { + code: 'if (a) { first(); } else if (b) { first(); } else { first(); }', + errors: [ + { + messageId: 'removeOrEditConditionalStructure', + line: 1, + column: 1, + endColumn: 63, + }, + ], + }, + { + code: 'if (a) { first(); second(); } else { first(); second(); }', + errors: [ + { + messageId: 'removeOrEditConditionalStructure', + line: 1, + column: 1, + endColumn: 58, + }, + ], + }, + { + code: 'if (a) { first(); second(); } else if (b) { first(); second(); } else { first(); second(); }', + errors: [ + { + messageId: 'removeOrEditConditionalStructure', + line: 1, + column: 1, + endColumn: 93, + }, + ], + }, + ], + }); - ruleTester.run('S3923 switch', rule, { - valid: [ - { - // Ok, no default - code: ` + ruleTester.run('S3923 switch', rule, { + valid: [ + { + // Ok, no default + code: ` switch (a) { case 1: first(); @@ -110,9 +111,9 @@ describe('S3923', () => { first(); second(); }`, - }, - { - code: ` + }, + { + code: ` switch (a) { case 1: first(); @@ -125,9 +126,9 @@ describe('S3923', () => { default: third(); }`, - }, - { - code: ` + }, + { + code: ` switch (a) { case 1: first(); @@ -139,11 +140,11 @@ describe('S3923', () => { break; default: }`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` switch (a) { case 1: first(); @@ -153,18 +154,18 @@ describe('S3923', () => { first(); second(); }`, - errors: [ - { - messageId: 'removeOrEditConditionalStructure', - line: 2, - endLine: 10, - column: 7, - endColumn: 8, - }, - ], - }, - { - code: ` + errors: [ + { + messageId: 'removeOrEditConditionalStructure', + line: 2, + endLine: 10, + column: 7, + endColumn: 8, + }, + ], + }, + { + code: ` switch (a) { case 1: first(); @@ -178,18 +179,18 @@ describe('S3923', () => { first(); second(); }`, - errors: [ - { - messageId: 'removeOrEditConditionalStructure', - line: 2, - endLine: 14, - column: 7, - endColumn: 8, - }, - ], - }, - { - code: ` + errors: [ + { + messageId: 'removeOrEditConditionalStructure', + line: 2, + endLine: 14, + column: 7, + endColumn: 8, + }, + ], + }, + { + code: ` switch (a) { case 1: first(); @@ -200,18 +201,18 @@ describe('S3923', () => { default: first(); }`, - errors: [ - { - messageId: 'removeOrEditConditionalStructure', - line: 2, - endLine: 11, - column: 7, - endColumn: 8, - }, - ], - }, - { - code: ` + errors: [ + { + messageId: 'removeOrEditConditionalStructure', + line: 2, + endLine: 11, + column: 7, + endColumn: 8, + }, + ], + }, + { + code: ` switch (a) { case 1: case 2: @@ -226,33 +227,34 @@ describe('S3923', () => { first(); second(); }`, - errors: [ - { - messageId: 'removeOrEditConditionalStructure', - line: 2, - endLine: 15, - column: 7, - endColumn: 8, - }, - ], - }, - ], - }); + errors: [ + { + messageId: 'removeOrEditConditionalStructure', + line: 2, + endLine: 15, + column: 7, + endColumn: 8, + }, + ], + }, + ], + }); - ruleTester.run('S3923 conditional', rule, { - valid: [{ code: 'a ? first : second;' }], - invalid: [ - { - code: 'a ? first : first;', - errors: [ - { - messageId: 'returnsTheSameValue', - line: 1, - column: 1, - endColumn: 18, - }, - ], - }, - ], + ruleTester.run('S3923 conditional', rule, { + valid: [{ code: 'a ? first : second;' }], + invalid: [ + { + code: 'a ? first : first;', + errors: [ + { + messageId: 'returnsTheSameValue', + line: 1, + column: 1, + endColumn: 18, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3972/unit.test.ts b/packages/jsts/src/rules/S3972/unit.test.ts index 6e9ece1870..ec208e92c0 100644 --- a/packages/jsts/src/rules/S3972/unit.test.ts +++ b/packages/jsts/src/rules/S3972/unit.test.ts @@ -16,61 +16,62 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3972', () => { - const ruleTester = new RuleTester(); + it('S3972', () => { + const ruleTester = new RuleTester(); - ruleTester.run('Conditionals should start on new lines', rule, { - valid: [ - { - code: ` + ruleTester.run('Conditionals should start on new lines', rule, { + valid: [ + { + code: ` if (cond1) if (cond2) { if (cond3) { } }`, - }, - { - code: ` + }, + { + code: ` if (cond1) { } else if (cond2) { } else if (cond3) { }`, - }, - { - code: ` + }, + { + code: ` if (cond1) { } if (cond2) { } else if (cond3) { }`, - }, - { - code: ` + }, + { + code: ` if (cond1) doSomething(); if (cond2) { }`, - }, - { - code: `foo(); if (cond) bar();`, - }, - { - // OK if everything is on one line - code: `if (cond1) foo(); if (cond2) bar();`, - }, - { - code: ` + }, + { + code: `foo(); if (cond) bar();`, + }, + { + // OK if everything is on one line + code: `if (cond1) foo(); if (cond2) bar();`, + }, + { + code: ` function myFunc() { if (cond1) { } else if (cond2) { } else if (cond3) { } }`, - }, - { - code: ` + }, + { + code: ` switch(x) { case 1: if (cond1) { @@ -85,43 +86,43 @@ describe('S3972', () => { } break; }`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` if (cond1) { } if (cond2) { }`, - errors: [ - { - messageId: 'sameLineCondition', - line: 3, - endLine: 3, - column: 9, - endColumn: 11, - suggestions: [ - { - messageId: 'suggestAddingElse', - output: ` + errors: [ + { + messageId: 'sameLineCondition', + line: 3, + endLine: 3, + column: 9, + endColumn: 11, + suggestions: [ + { + messageId: 'suggestAddingElse', + output: ` if (cond1) { } else if (cond2) { }`, - }, - { - messageId: 'suggestAddingNewline', - output: ` + }, + { + messageId: 'suggestAddingNewline', + output: ` if (cond1) { } if (cond2) { }`, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` switch(x) { case 1: if (cond1) { @@ -136,31 +137,31 @@ describe('S3972', () => { } break; }`, - options: ['sonar-runtime'], - errors: [ - { - messageId: 'sonarRuntime', - data: { - sonarRuntimeData: JSON.stringify({ - message: 'Move this "if" to a new line or add the missing "else".', - secondaryLocations: [ - { - column: 10, - line: 6, - endColumn: 11, - endLine: 6, - }, - ], - }), - }, - line: 6, - endLine: 6, - column: 13, - endColumn: 15, - suggestions: [ - { - messageId: 'suggestAddingElse', - output: ` + options: ['sonar-runtime'], + errors: [ + { + messageId: 'sonarRuntime', + data: { + sonarRuntimeData: JSON.stringify({ + message: 'Move this "if" to a new line or add the missing "else".', + secondaryLocations: [ + { + column: 10, + line: 6, + endColumn: 11, + endLine: 6, + }, + ], + }), + }, + line: 6, + endLine: 6, + column: 13, + endColumn: 15, + suggestions: [ + { + messageId: 'suggestAddingElse', + output: ` switch(x) { case 1: if (cond1) { @@ -175,10 +176,10 @@ describe('S3972', () => { } break; }`, - }, - { - messageId: 'suggestAddingNewline', - output: ` + }, + { + messageId: 'suggestAddingNewline', + output: ` switch(x) { case 1: if (cond1) { @@ -194,32 +195,32 @@ describe('S3972', () => { } break; }`, - }, - ], - }, - { - messageId: 'sonarRuntime', - data: { - sonarRuntimeData: JSON.stringify({ - message: 'Move this "if" to a new line or add the missing "else".', - secondaryLocations: [ - { - column: 10, - line: 11, - endColumn: 11, - endLine: 11, - }, - ], - }), + }, + ], }, - line: 11, - endLine: 11, - column: 13, - endColumn: 15, - suggestions: [ - { - messageId: 'suggestAddingElse', - output: ` + { + messageId: 'sonarRuntime', + data: { + sonarRuntimeData: JSON.stringify({ + message: 'Move this "if" to a new line or add the missing "else".', + secondaryLocations: [ + { + column: 10, + line: 11, + endColumn: 11, + endLine: 11, + }, + ], + }), + }, + line: 11, + endLine: 11, + column: 13, + endColumn: 15, + suggestions: [ + { + messageId: 'suggestAddingElse', + output: ` switch(x) { case 1: if (cond1) { @@ -234,10 +235,10 @@ describe('S3972', () => { } break; }`, - }, - { - messageId: 'suggestAddingNewline', - output: ` + }, + { + messageId: 'suggestAddingNewline', + output: ` switch(x) { case 1: if (cond1) { @@ -253,95 +254,95 @@ describe('S3972', () => { } break; }`, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` if (cond1) { } else if (cond2) { } if (cond3) { }`, - options: ['sonar-runtime'], - errors: [ - { - messageId: 'sonarRuntime', - data: { - sonarRuntimeData: JSON.stringify({ - message: 'Move this "if" to a new line or add the missing "else".', - secondaryLocations: [ - { - column: 6, - line: 4, - endColumn: 7, - endLine: 4, - }, - ], - }), - }, - suggestions: [ - { - messageId: 'suggestAddingElse', - output: ` + options: ['sonar-runtime'], + errors: [ + { + messageId: 'sonarRuntime', + data: { + sonarRuntimeData: JSON.stringify({ + message: 'Move this "if" to a new line or add the missing "else".', + secondaryLocations: [ + { + column: 6, + line: 4, + endColumn: 7, + endLine: 4, + }, + ], + }), + }, + suggestions: [ + { + messageId: 'suggestAddingElse', + output: ` if (cond1) { } else if (cond2) { } else if (cond3) { }`, - }, - { - messageId: 'suggestAddingNewline', - output: ` + }, + { + messageId: 'suggestAddingNewline', + output: ` if (cond1) { } else if (cond2) { } if (cond3) { }`, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` if (cond1) if (cond2) { if (cond3) { } if (cond4) { } }`, - options: ['sonar-runtime'], - errors: [ - { - messageId: 'sonarRuntime', - data: { - sonarRuntimeData: JSON.stringify({ - message: 'Move this "if" to a new line or add the missing "else".', - secondaryLocations: [ - { - column: 10, - line: 5, - endColumn: 11, - endLine: 5, - }, - ], - }), - }, - suggestions: [ - { - messageId: 'suggestAddingElse', - output: ` + options: ['sonar-runtime'], + errors: [ + { + messageId: 'sonarRuntime', + data: { + sonarRuntimeData: JSON.stringify({ + message: 'Move this "if" to a new line or add the missing "else".', + secondaryLocations: [ + { + column: 10, + line: 5, + endColumn: 11, + endLine: 5, + }, + ], + }), + }, + suggestions: [ + { + messageId: 'suggestAddingElse', + output: ` if (cond1) if (cond2) { if (cond3) { } else if (cond4) { } }`, - }, - { - messageId: 'suggestAddingNewline', - output: ` + }, + { + messageId: 'suggestAddingNewline', + output: ` if (cond1) if (cond2) { if (cond3) { @@ -349,50 +350,50 @@ describe('S3972', () => { if (cond4) { } }`, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` function myFunc() { if (cond1) { } else if (cond2) { } if (cond3) { } }`, - options: ['sonar-runtime'], - errors: [ - { - messageId: 'sonarRuntime', - data: { - sonarRuntimeData: JSON.stringify({ - message: 'Move this "if" to a new line or add the missing "else".', - secondaryLocations: [ - { - column: 8, - line: 5, - endColumn: 9, - endLine: 5, - }, - ], - }), - }, - suggestions: [ - { - messageId: 'suggestAddingElse', - output: ` + options: ['sonar-runtime'], + errors: [ + { + messageId: 'sonarRuntime', + data: { + sonarRuntimeData: JSON.stringify({ + message: 'Move this "if" to a new line or add the missing "else".', + secondaryLocations: [ + { + column: 8, + line: 5, + endColumn: 9, + endLine: 5, + }, + ], + }), + }, + suggestions: [ + { + messageId: 'suggestAddingElse', + output: ` function myFunc() { if (cond1) { } else if (cond2) { } else if (cond3) { } }`, - }, - { - messageId: 'suggestAddingNewline', - output: ` + }, + { + messageId: 'suggestAddingNewline', + output: ` function myFunc() { if (cond1) { } else if (cond2) { @@ -400,59 +401,60 @@ describe('S3972', () => { if (cond3) { } }`, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` function myFunc() { foo(); if (cond1) { } if (cond2) { } }`, - options: ['sonar-runtime'], - errors: [ - { - messageId: 'sonarRuntime', - data: { - sonarRuntimeData: JSON.stringify({ - message: 'Move this "if" to a new line or add the missing "else".', - secondaryLocations: [ - { - column: 8, - line: 4, - endColumn: 9, - endLine: 4, - }, - ], - }), - }, - suggestions: [ - { - messageId: 'suggestAddingElse', - output: ` + options: ['sonar-runtime'], + errors: [ + { + messageId: 'sonarRuntime', + data: { + sonarRuntimeData: JSON.stringify({ + message: 'Move this "if" to a new line or add the missing "else".', + secondaryLocations: [ + { + column: 8, + line: 4, + endColumn: 9, + endLine: 4, + }, + ], + }), + }, + suggestions: [ + { + messageId: 'suggestAddingElse', + output: ` function myFunc() { foo(); if (cond1) { } else if (cond2) { } }`, - }, - { - messageId: 'suggestAddingNewline', - output: ` + }, + { + messageId: 'suggestAddingNewline', + output: ` function myFunc() { foo(); if (cond1) { } if (cond2) { } }`, - }, - ], - }, - ], - }, - ], + }, + ], + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3973/unit.test.ts b/packages/jsts/src/rules/S3973/unit.test.ts index 582a22ad64..7ad3a62786 100644 --- a/packages/jsts/src/rules/S3973/unit.test.ts +++ b/packages/jsts/src/rules/S3973/unit.test.ts @@ -16,21 +16,22 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3973', () => { - const ruleTester = new RuleTester(); + it('S3973', () => { + const ruleTester = new RuleTester(); - ruleTester.run(`A conditionally executed single line should be denoted by indentation`, rule, { - valid: [ - { - code: ` + ruleTester.run(`A conditionally executed single line should be denoted by indentation`, rule, { + valid: [ + { + code: ` if (x > 0) doTheThing(); doTheOtherThing();`, - }, - { - code: ` + }, + { + code: ` while (x <= 10) doTheThing(); doTheOtherThing(); @@ -39,18 +40,18 @@ describe('S3973', () => { doTheThing(); doTheOtherThing(); }`, - }, - { - code: ` + }, + { + code: ` if (x == 5) doTheThing(); else if (x == 6) doTheThing(); else doTheThing();`, - }, - { - code: ` + }, + { + code: ` if (x > 0) { doTheThing(); doTheOtherThing(); @@ -61,9 +62,9 @@ describe('S3973', () => { doTheThing(); doTheOtherThing(); }`, - }, - { - code: ` + }, + { + code: ` for (x in arr) doTheThing(); doTheOtherThing(); @@ -72,86 +73,86 @@ describe('S3973', () => { doTheThing(); doTheOtherThing(); }`, - }, - { - code: ` + }, + { + code: ` if (something) { //... some logic doSomething(); } else doSomethingElse();`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` if (x > 0) // Noncompliant [[ID=ID1]] {{}} doTheThing(); doTheOtherThing(); `, - errors: [ - { - message: `{\"message\":\"Use curly braces or indentation to denote the code conditionally executed by this \\\"if\\\".\",\"secondaryLocations\":[{\"column\":8,\"line\":3,\"endColumn\":18,\"endLine\":3}]}`, - line: 2, - column: 9, - endLine: 2, - endColumn: 11, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: `{\"message\":\"Use curly braces or indentation to denote the code conditionally executed by this \\\"if\\\".\",\"secondaryLocations\":[{\"column\":8,\"line\":3,\"endColumn\":18,\"endLine\":3}]}`, + line: 2, + column: 9, + endLine: 2, + endColumn: 11, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` if (cond) { } else // Noncompliant foo(); `, - errors: [ - { - message: `{\"message\":\"Use curly braces or indentation to denote the code conditionally executed by this \\\"else\\\".\",\"secondaryLocations\":[{\"column\":8,\"line\":4,\"endColumn\":11,\"endLine\":4}]}`, - line: 3, - column: 11, - endLine: 3, - endColumn: 15, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: `{\"message\":\"Use curly braces or indentation to denote the code conditionally executed by this \\\"else\\\".\",\"secondaryLocations\":[{\"column\":8,\"line\":4,\"endColumn\":11,\"endLine\":4}]}`, + line: 3, + column: 11, + endLine: 3, + endColumn: 15, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` while (x <= 10) // Noncompliant doTheThing(); doTheOtherThing(); `, - errors: [ - { - message: `{\"message\":\"Use curly braces or indentation to denote the code conditionally executed by this \\\"while\\\".\",\"secondaryLocations\":[{\"column\":10,\"line\":3,\"endColumn\":20,\"endLine\":3}]}`, - line: 2, - column: 11, - endLine: 2, - endColumn: 16, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: `{\"message\":\"Use curly braces or indentation to denote the code conditionally executed by this \\\"while\\\".\",\"secondaryLocations\":[{\"column\":10,\"line\":3,\"endColumn\":20,\"endLine\":3}]}`, + line: 2, + column: 11, + endLine: 2, + endColumn: 16, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` for (x in arr) // Noncompliant doTheThing(); doTheOtherThing();`, - errors: [ - { - message: `{\"message\":\"Use curly braces or indentation to denote the code conditionally executed by this \\\"for\\\".\",\"secondaryLocations\":[{\"column\":10,\"line\":3,\"endColumn\":20,\"endLine\":3}]}`, - line: 2, - column: 11, - endLine: 2, - endColumn: 14, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: `{\"message\":\"Use curly braces or indentation to denote the code conditionally executed by this \\\"for\\\".\",\"secondaryLocations\":[{\"column\":10,\"line\":3,\"endColumn\":20,\"endLine\":3}]}`, + line: 2, + column: 11, + endLine: 2, + endColumn: 14, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` if (x == 5) // Noncompliant doTheThing(); else if (x == 6) // Noncompliant @@ -159,10 +160,10 @@ describe('S3973', () => { else // Noncompliant doTheThing(); `, - errors: 3, - }, - { - code: ` + errors: 3, + }, + { + code: ` for (x = 1; x <= 10; x++) // Noncompliant, only one error at line 2 doTheThing(); doTheOtherThing(); @@ -173,20 +174,21 @@ describe('S3973', () => { doTheThing(); doTheOtherThing(); }`, - errors: [ - { - message: - 'Use curly braces or indentation to denote the code conditionally executed by this "for".', - line: 2, - }, - ], - }, - { - code: ` + errors: [ + { + message: + 'Use curly braces or indentation to denote the code conditionally executed by this "for".', + line: 2, + }, + ], + }, + { + code: ` if (cond) // Noncompliant, negative indentation foo();`, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3981/unit.test.ts b/packages/jsts/src/rules/S3981/unit.test.ts index c50c5a83a4..fa1215b791 100644 --- a/packages/jsts/src/rules/S3981/unit.test.ts +++ b/packages/jsts/src/rules/S3981/unit.test.ts @@ -16,15 +16,16 @@ */ import { rule } from './rule.js'; import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3981', () => { - const ruleTester = new DefaultParserRuleTester(); + it('S3981', () => { + const ruleTester = new DefaultParserRuleTester(); - ruleTester.run('Collection sizes and array length comparisons should make sense', rule, { - valid: [ - { - code: ` + ruleTester.run('Collection sizes and array length comparisons should make sense', rule, { + valid: [ + { + code: ` if (collections.length < 1) {} if (collections.length > 0) {} if (collections.length <= 1) {} @@ -33,92 +34,92 @@ describe('S3981', () => { if (collections.length < 5 + 0){} if (collections.size() >= 0) {} `, - }, - ], - invalid: [ - { - code: `if (collection.size < 0) {}`, - errors: [ - { - messageId: 'fixCollectionSizeCheck', - data: { - propertyName: 'size', - objectName: 'collection', - }, - line: 1, - endLine: 1, - column: 5, - endColumn: 24, - suggestions: [ - { - messageId: 'suggestFixedSizeCheck', - data: { - operation: 'size', - operator: '==', - }, - output: `if (collection.size == 0) {}`, + }, + ], + invalid: [ + { + code: `if (collection.size < 0) {}`, + errors: [ + { + messageId: 'fixCollectionSizeCheck', + data: { + propertyName: 'size', + objectName: 'collection', }, - ], - }, - ], - }, - { - code: `if (collection.length < 0) {}`, - errors: [ - { - messageId: 'fixCollectionSizeCheck', - data: { - propertyName: 'length', - objectName: 'collection', + line: 1, + endLine: 1, + column: 5, + endColumn: 24, + suggestions: [ + { + messageId: 'suggestFixedSizeCheck', + data: { + operation: 'size', + operator: '==', + }, + output: `if (collection.size == 0) {}`, + }, + ], }, - line: 1, - endLine: 1, - column: 5, - endColumn: 26, - suggestions: [ - { - desc: 'Use "==" for length check', - output: `if (collection.length == 0) {}`, + ], + }, + { + code: `if (collection.length < 0) {}`, + errors: [ + { + messageId: 'fixCollectionSizeCheck', + data: { + propertyName: 'length', + objectName: 'collection', }, - ], - }, - ], - }, - { - code: `if (collection.length >= 0) {}`, - errors: [ - { - messageId: 'fixCollectionSizeCheck', - data: { - propertyName: 'length', - objectName: 'collection', - }, - line: 1, - endLine: 1, - column: 5, - endColumn: 27, - suggestions: [ - { - messageId: 'suggestFixedSizeCheck', - data: { - operation: 'length', - operator: '>', + line: 1, + endLine: 1, + column: 5, + endColumn: 26, + suggestions: [ + { + desc: 'Use "==" for length check', + output: `if (collection.length == 0) {}`, }, - output: `if (collection.length > 0) {}`, + ], + }, + ], + }, + { + code: `if (collection.length >= 0) {}`, + errors: [ + { + messageId: 'fixCollectionSizeCheck', + data: { + propertyName: 'length', + objectName: 'collection', }, - ], - }, - ], - }, - ], - }); + line: 1, + endLine: 1, + column: 5, + endColumn: 27, + suggestions: [ + { + messageId: 'suggestFixedSizeCheck', + data: { + operation: 'length', + operator: '>', + }, + output: `if (collection.length > 0) {}`, + }, + ], + }, + ], + }, + ], + }); - const ruleTesterTs = new RuleTester(); + const ruleTesterTs = new RuleTester(); - ruleTesterTs.run('Collection sizes and array length comparisons should make sense', rule, { - valid: [ - { - code: ` + ruleTesterTs.run('Collection sizes and array length comparisons should make sense', rule, { + valid: [ + { + code: ` const arr = []; if (arr.length < 1) {} if (arr.length > 0) {} @@ -127,9 +128,9 @@ describe('S3981', () => { if (arr.length < 50) {} if (arr.length < 5 + 0) {} `, - }, - { - code: ` + }, + { + code: ` const obj = {length: -4, size: -5, foobar: 42}; if (obj.foobar >= 0) {} if (obj.size >= 0) {} @@ -138,205 +139,206 @@ describe('S3981', () => { if (obj.length < 53) {} if (obj.length > 0) {} `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const arr = []; if (arr.length < 0) {} `, - errors: [ - { - messageId: 'fixCollectionSizeCheck', - data: { - propertyName: 'length', - objectName: 'arr', - }, - line: 3, - endLine: 3, - column: 11, - endColumn: 25, - suggestions: [ - { - desc: 'Use "==" for length check', - output: ` + errors: [ + { + messageId: 'fixCollectionSizeCheck', + data: { + propertyName: 'length', + objectName: 'arr', + }, + line: 3, + endLine: 3, + column: 11, + endColumn: 25, + suggestions: [ + { + desc: 'Use "==" for length check', + output: ` const arr = []; if (arr.length == 0) {} `, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` const arr = []; if (arr.length >= 0) {} `, - errors: [ - { - messageId: 'fixCollectionSizeCheck', - data: { - propertyName: 'length', - objectName: 'arr', - }, - line: 3, - endLine: 3, - column: 11, - endColumn: 26, - suggestions: [ - { - desc: 'Use ">" for length check', - output: ` + errors: [ + { + messageId: 'fixCollectionSizeCheck', + data: { + propertyName: 'length', + objectName: 'arr', + }, + line: 3, + endLine: 3, + column: 11, + endColumn: 26, + suggestions: [ + { + desc: 'Use ">" for length check', + output: ` const arr = []; if (arr.length > 0) {} `, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` const arr = new Array(); if (arr.length >= 0) {} `, - errors: [ - { - messageId: 'fixCollectionSizeCheck', - data: { - propertyName: 'length', - objectName: 'arr', - }, - line: 3, - endLine: 3, - column: 11, - endColumn: 26, - suggestions: [ - { - desc: 'Use ">" for length check', - output: ` + errors: [ + { + messageId: 'fixCollectionSizeCheck', + data: { + propertyName: 'length', + objectName: 'arr', + }, + line: 3, + endLine: 3, + column: 11, + endColumn: 26, + suggestions: [ + { + desc: 'Use ">" for length check', + output: ` const arr = new Array(); if (arr.length > 0) {} `, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` const set = new Set(); if (set.length < 0) {} `, - errors: [ - { - messageId: 'fixCollectionSizeCheck', - data: { - propertyName: 'length', - objectName: 'set', - }, - line: 3, - endLine: 3, - column: 11, - endColumn: 25, - suggestions: [ - { - desc: 'Use "==" for length check', - output: ` + errors: [ + { + messageId: 'fixCollectionSizeCheck', + data: { + propertyName: 'length', + objectName: 'set', + }, + line: 3, + endLine: 3, + column: 11, + endColumn: 25, + suggestions: [ + { + desc: 'Use "==" for length check', + output: ` const set = new Set(); if (set.length == 0) {} `, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` const map = new Map(); if (map.length < 0) {} `, - errors: [ - { - messageId: 'fixCollectionSizeCheck', - data: { - propertyName: 'length', - objectName: 'map', - }, - line: 3, - endLine: 3, - column: 11, - endColumn: 25, - suggestions: [ - { - desc: 'Use "==" for length check', - output: ` + errors: [ + { + messageId: 'fixCollectionSizeCheck', + data: { + propertyName: 'length', + objectName: 'map', + }, + line: 3, + endLine: 3, + column: 11, + endColumn: 25, + suggestions: [ + { + desc: 'Use "==" for length check', + output: ` const map = new Map(); if (map.length == 0) {} `, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` const set = new WeakSet(); if (set.length < 0) {} `, - errors: [ - { - messageId: 'fixCollectionSizeCheck', - data: { - propertyName: 'length', - objectName: 'set', - }, - line: 3, - endLine: 3, - column: 11, - endColumn: 25, - suggestions: [ - { - desc: 'Use "==" for length check', - output: ` + errors: [ + { + messageId: 'fixCollectionSizeCheck', + data: { + propertyName: 'length', + objectName: 'set', + }, + line: 3, + endLine: 3, + column: 11, + endColumn: 25, + suggestions: [ + { + desc: 'Use "==" for length check', + output: ` const set = new WeakSet(); if (set.length == 0) {} `, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` const map = new WeakMap(); if (map.length < 0) {} `, - errors: [ - { - messageId: 'fixCollectionSizeCheck', - data: { - propertyName: 'length', - objectName: 'map', - }, - line: 3, - endLine: 3, - column: 11, - endColumn: 25, - suggestions: [ - { - desc: 'Use "==" for length check', - output: ` + errors: [ + { + messageId: 'fixCollectionSizeCheck', + data: { + propertyName: 'length', + objectName: 'map', + }, + line: 3, + endLine: 3, + column: 11, + endColumn: 25, + suggestions: [ + { + desc: 'Use "==" for length check', + output: ` const map = new WeakMap(); if (map.length == 0) {} `, - }, - ], - }, - ], - }, - ], + }, + ], + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S3984/unit.test.ts b/packages/jsts/src/rules/S3984/unit.test.ts index 17d301ef0e..b991c2eb57 100644 --- a/packages/jsts/src/rules/S3984/unit.test.ts +++ b/packages/jsts/src/rules/S3984/unit.test.ts @@ -16,71 +16,73 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S3984', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Exception should not be created without being thrown', rule, { - valid: [ - { - code: `foo(new Error());`, - }, - { - code: `foo(TypeError);`, - }, - { - code: `throw new Error();`, - }, - { - code: `new LooksLikeAnError().doSomething();`, - }, - ], - invalid: [ - { - code: `new Error();`, - errors: [ - { - message: 'Throw this error or remove this useless statement.', - line: 1, - column: 1, - endLine: 1, - endColumn: 12, - suggestions: [ - { - desc: 'Throw this error', - output: 'throw new Error();', - }, - ], - }, - ], - }, - { - code: `new TypeError();`, - errors: 1, - }, - { - code: `new MyError();`, - errors: 1, - }, - { - code: `new A.MyError();`, - errors: 1, - }, - { - code: `new A(function () { + it('S3984', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Exception should not be created without being thrown', rule, { + valid: [ + { + code: `foo(new Error());`, + }, + { + code: `foo(TypeError);`, + }, + { + code: `throw new Error();`, + }, + { + code: `new LooksLikeAnError().doSomething();`, + }, + ], + invalid: [ + { + code: `new Error();`, + errors: [ + { + message: 'Throw this error or remove this useless statement.', + line: 1, + column: 1, + endLine: 1, + endColumn: 12, + suggestions: [ + { + desc: 'Throw this error', + output: 'throw new Error();', + }, + ], + }, + ], + }, + { + code: `new TypeError();`, + errors: 1, + }, + { + code: `new MyError();`, + errors: 1, + }, + { + code: `new A.MyError();`, + errors: 1, + }, + { + code: `new A(function () { new SomeError(); });`, - errors: 1, - }, - { - code: `(new MyException());`, - errors: [ - { - messageId: 'throwOrRemoveError', - suggestions: [{ desc: 'Throw this error', output: 'throw (new MyException());' }], - }, - ], - }, - ], + errors: 1, + }, + { + code: `(new MyException());`, + errors: [ + { + messageId: 'throwOrRemoveError', + suggestions: [{ desc: 'Throw this error', output: 'throw (new MyException());' }], + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4023/unit.test.ts b/packages/jsts/src/rules/S4023/unit.test.ts index b5964d2bc9..ba2357a991 100644 --- a/packages/jsts/src/rules/S4023/unit.test.ts +++ b/packages/jsts/src/rules/S4023/unit.test.ts @@ -16,34 +16,36 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4023', () => { - const ruleTester = new RuleTester(); - ruleTester.run(`Decorated rule should provide suggestion`, rule, { - valid: [ - { - code: 'interface A { x: string }', - }, - { - code: 'interface A { x: string, y: string }; interface B extends Pick {}', - }, - ], - invalid: [ - { - code: 'interface A {}', - errors: 1, - }, - { - code: 'interface A extends "foo" {}', - errors: 1, - output: 'type A = "foo"', - }, - { - code: 'interface A extends Z {}', - errors: 1, - output: 'type A = Z', - }, - ], + it('S4023', () => { + const ruleTester = new RuleTester(); + ruleTester.run(`Decorated rule should provide suggestion`, rule, { + valid: [ + { + code: 'interface A { x: string }', + }, + { + code: 'interface A { x: string, y: string }; interface B extends Pick {}', + }, + ], + invalid: [ + { + code: 'interface A {}', + errors: 1, + }, + { + code: 'interface A extends "foo" {}', + errors: 1, + output: 'type A = "foo"', + }, + { + code: 'interface A extends Z {}', + errors: 1, + output: 'type A = Z', + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4030/unit.test.ts b/packages/jsts/src/rules/S4030/unit.test.ts index cf0ac1f44a..12740e31f7 100644 --- a/packages/jsts/src/rules/S4030/unit.test.ts +++ b/packages/jsts/src/rules/S4030/unit.test.ts @@ -16,29 +16,30 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4030', () => { - const ruleTester = new RuleTester(); + it('S4030', () => { + const ruleTester = new RuleTester(); - function invalidTest(code: string) { - const line = code.split('\n').findIndex(str => str.includes('// Noncompliant')) + 1; - return { - code, - errors: [ - { - messageId: 'unusedCollection', - line, - endLine: line, - }, - ], - }; - } + function invalidTest(code: string) { + const line = code.split('\n').findIndex(str => str.includes('// Noncompliant')) + 1; + return { + code, + errors: [ + { + messageId: 'unusedCollection', + line, + endLine: line, + }, + ], + }; + } - ruleTester.run('Collection contents should be used', rule, { - valid: [ - { - code: ` + ruleTester.run('Collection contents should be used', rule, { + valid: [ + { + code: ` function okUnused() { let x = [1, 2]; } @@ -85,9 +86,9 @@ describe('S4030', () => { y.push(1); return x; }`, - }, - { - code: ` + }, + { + code: ` function parameterUpdated(p) { p.push(1); } @@ -133,9 +134,9 @@ describe('S4030', () => { this.myArray.push(""); // OK for properties } }`, - }, - { - code: ` + }, + { + code: ` function nok() { let array = new Uint16Array(2); // FN array[1] = 43; @@ -145,42 +146,42 @@ describe('S4030', () => { let bufferView = new Uint16Array(buffer); bufferView[1] = 43; }`, - }, - { - code: `var subgoups = [], sub; //both are compliant + }, + { + code: `var subgoups = [], sub; //both are compliant subgroups.push(sub = []); //sub is used here sub.push(node); return subgroups; `, - }, - { - code: ` + }, + { + code: ` let array = []; for (let i in array) { // used here console.log(i); }`, - }, - { - code: ` + }, + { + code: ` export const array = []; array.push(1); `, - }, - { - code: `export const collection = new Map()`, - }, - { - code: ` + }, + { + code: `export const collection = new Map()`, + }, + { + code: ` const a = {foo: false}; const xs = [a]; xs[0].foo = true; `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function nok() { let x = [1, 2]; x.push(1); @@ -190,59 +191,60 @@ describe('S4030', () => { x.pop(); x.reverse(); }`, - errors: [ - { - messageId: 'unusedCollection', - line: 3, - column: 13, - endLine: 3, - endColumn: 14, - }, - ], - }, - invalidTest(`function nok2() { + errors: [ + { + messageId: 'unusedCollection', + line: 3, + column: 13, + endLine: 3, + endColumn: 14, + }, + ], + }, + invalidTest(`function nok2() { let arrayConstructor = new Array(); // Noncompliant arrayConstructor[1] = 42; } `), - invalidTest(`function nok3() { + invalidTest(`function nok3() { let arrayWithoutNew = Array(); // Noncompliant arrayWithoutNew[1] = 42; } `), - invalidTest(`function nok4() { + invalidTest(`function nok4() { let x: number[]; // Noncompliant x = new Array(); x[1] = 42; }`), - invalidTest(`function nok41() { + invalidTest(`function nok41() { let x; // Noncompliant x = []; x.push("a"); }`), - invalidTest(`function nok5() { + invalidTest(`function nok5() { let myMap = new Map(); // Noncompliant myMap.set(1, "foo1"); myMap.clear(); }`), - invalidTest(`function nok6() { + invalidTest(`function nok6() { let mySet = new Set(); // Noncompliant mySet.add("foo1"); mySet.delete("foo1"); mySet = new Set(); }`), - invalidTest(`function nok7() { + invalidTest(`function nok7() { let mySet = new WeakSet(); // Noncompliant mySet.add({}); mySet.delete({}); }`), - invalidTest(`function nestedFunctionInVarDeclaration() { + invalidTest(`function nestedFunctionInVarDeclaration() { var x = [], // Noncompliant f = function() { x = []; } x.push(); }`), - ], + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4043/unit.test.ts b/packages/jsts/src/rules/S4043/unit.test.ts index 87f5d398c5..e514e9d6c3 100644 --- a/packages/jsts/src/rules/S4043/unit.test.ts +++ b/packages/jsts/src/rules/S4043/unit.test.ts @@ -16,14 +16,15 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4043', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Array-mutating methods should not be used misleadingly.', rule, { - valid: [ - { - code: ` + it('S4043', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Array-mutating methods should not be used misleadingly.', rule, { + valid: [ + { + code: ` let a = []; let d; @@ -40,12 +41,12 @@ describe('S4043', () => { a = a.reverse(); a = a.sort(); `, - }, - { - code: `const c = [1, 2, 3].reverse();`, - }, - { - code: ` + }, + { + code: `const c = [1, 2, 3].reverse();`, + }, + { + code: ` function foo() { const keys = []; // fill keys... @@ -56,9 +57,9 @@ describe('S4043', () => { return s.split("").reverse().join(); } `, - }, - { - code: ` + }, + { + code: ` class Bar { field: string[]; @@ -73,18 +74,18 @@ describe('S4043', () => { return [...this.field]; } }`, - }, - { - code: ` + }, + { + code: ` class NotArray { public reverse() {} } const notArray = new NotArray(); // ok const notArrayReversed = notArray.reverse();`, - }, - { - code: ` + }, + { + code: ` class WithGetter { _groups: string[]; @@ -98,185 +99,185 @@ describe('S4043', () => { return groups; } }`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` let a = []; const b = a?.sort(); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` let a = []; let d; const b = a.reverse(); const bb = a.sort(); d = a.reverse(); `, - errors: [ - { - message: - 'Move this array "reverse" operation to a separate statement or replace it with "toReversed".', - line: 4, - endLine: 4, - column: 19, - endColumn: 30, - suggestions: [ - { - desc: 'Replace with "toReversed" method', - output: ` + errors: [ + { + message: + 'Move this array "reverse" operation to a separate statement or replace it with "toReversed".', + line: 4, + endLine: 4, + column: 19, + endColumn: 30, + suggestions: [ + { + desc: 'Replace with "toReversed" method', + output: ` let a = []; let d; const b = a.toReversed(); const bb = a.sort(); d = a.reverse(); `, - }, - ], - }, - { - message: - 'Move this array "sort" operation to a separate statement or replace it with "toSorted".', - line: 5, - endLine: 5, - column: 20, - endColumn: 28, - suggestions: [ - { - desc: 'Replace with "toSorted" method', - output: ` + }, + ], + }, + { + message: + 'Move this array "sort" operation to a separate statement or replace it with "toSorted".', + line: 5, + endLine: 5, + column: 20, + endColumn: 28, + suggestions: [ + { + desc: 'Replace with "toSorted" method', + output: ` let a = []; let d; const b = a.reverse(); const bb = a.toSorted(); d = a.reverse(); `, - }, - ], - }, - { - message: - 'Move this array "reverse" operation to a separate statement or replace it with "toReversed".', - line: 6, - endLine: 6, - column: 13, - endColumn: 24, - suggestions: [ - { - desc: 'Replace with "toReversed" method', - output: ` + }, + ], + }, + { + message: + 'Move this array "reverse" operation to a separate statement or replace it with "toReversed".', + line: 6, + endLine: 6, + column: 13, + endColumn: 24, + suggestions: [ + { + desc: 'Replace with "toReversed" method', + output: ` let a = []; let d; const b = a.reverse(); const bb = a.sort(); d = a.toReversed(); `, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` let b = []; const a = b["sort"]() const a = b['sort']() const a = b["reverse"]() const a = b['reverse']() `, - errors: [ - { - message: - 'Move this array "sort" operation to a separate statement or replace it with "toSorted".', - suggestions: [ - { - desc: 'Replace with "toSorted" method', - output: ` + errors: [ + { + message: + 'Move this array "sort" operation to a separate statement or replace it with "toSorted".', + suggestions: [ + { + desc: 'Replace with "toSorted" method', + output: ` let b = []; const a = b["toSorted"]() const a = b['sort']() const a = b["reverse"]() const a = b['reverse']() `, - }, - ], - }, - { - message: - 'Move this array "sort" operation to a separate statement or replace it with "toSorted".', - suggestions: [ - { - desc: 'Replace with "toSorted" method', - output: ` + }, + ], + }, + { + message: + 'Move this array "sort" operation to a separate statement or replace it with "toSorted".', + suggestions: [ + { + desc: 'Replace with "toSorted" method', + output: ` let b = []; const a = b["sort"]() const a = b['toSorted']() const a = b["reverse"]() const a = b['reverse']() `, - }, - ], - }, - { - message: - 'Move this array "reverse" operation to a separate statement or replace it with "toReversed".', - suggestions: [ - { - desc: 'Replace with "toReversed" method', - output: ` + }, + ], + }, + { + message: + 'Move this array "reverse" operation to a separate statement or replace it with "toReversed".', + suggestions: [ + { + desc: 'Replace with "toReversed" method', + output: ` let b = []; const a = b["sort"]() const a = b['sort']() const a = b["toReversed"]() const a = b['reverse']() `, - }, - ], - }, - { - message: - 'Move this array "reverse" operation to a separate statement or replace it with "toReversed".', - suggestions: [ - { - desc: 'Replace with "toReversed" method', - output: ` + }, + ], + }, + { + message: + 'Move this array "reverse" operation to a separate statement or replace it with "toReversed".', + suggestions: [ + { + desc: 'Replace with "toReversed" method', + output: ` let b = []; const a = b["sort"]() const a = b['sort']() const a = b["reverse"]() const a = b['toReversed']() `, - }, - ], - }, - ], - }, - { - code: `function foo() { + }, + ], + }, + ], + }, + { + code: `function foo() { const keys = []; // fill keys... const x = keys.reverse(); }`, - errors: 1, - }, - { - code: `function reverseAndJoin() { + errors: 1, + }, + { + code: `function reverseAndJoin() { const a = [1, 2, 3]; const x = a.reverse().join(); }`, - errors: 1, - }, - { - code: `const a = [1, 2, 3]; + errors: 1, + }, + { + code: `const a = [1, 2, 3]; function something(a: string[]) {} something(a.reverse());`, - errors: 1, - }, - { - code: `class Bar { + errors: 1, + }, + { + code: `class Bar { field: string[]; public method() { @@ -284,85 +285,86 @@ describe('S4043', () => { const bb = this.field.sort(); } }`, - errors: 2, - }, - { - code: `function qux(a: string[][]) { + errors: 2, + }, + { + code: `function qux(a: string[][]) { return a.map(b => b.reverse()); }`, - errors: 1, - }, - { - code: `function foo(a: string[][]) { + errors: 1, + }, + { + code: `function foo(a: string[][]) { return function(a: string[][]) { let b; b = a.reverse(); } }`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` function foo() { let a = []; return a.length > 0 && a.reverse(); }`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const x = ["foo", "bar", "baz"]; const y = x.sort();`, - errors: [ - { - messageId: 'moveMethod', - suggestions: [ - { - desc: 'Replace with "toSorted" method', - output: ` + errors: [ + { + messageId: 'moveMethod', + suggestions: [ + { + desc: 'Replace with "toSorted" method', + output: ` const x = ["foo", "bar", "baz"]; const y = x.toSorted();`, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` const x = [true, false]; const y = x['reverse']();`, - errors: [ - { - messageId: 'moveMethod', - suggestions: [ - { - desc: 'Replace with "toReversed" method', - output: ` + errors: [ + { + messageId: 'moveMethod', + suggestions: [ + { + desc: 'Replace with "toReversed" method', + output: ` const x = [true, false]; const y = x['toReversed']();`, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` const x = ["foo", "bar", "baz"]; const y = x.sort((a, b) => true);`, - errors: [ - { - messageId: 'moveMethod', - suggestions: [ - { - desc: 'Replace with "toSorted" method', - output: ` + errors: [ + { + messageId: 'moveMethod', + suggestions: [ + { + desc: 'Replace with "toSorted" method', + output: ` const x = ["foo", "bar", "baz"]; const y = x.toSorted((a, b) => true);`, - }, - ], - }, - ], - }, - ], + }, + ], + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4123/unit.test.ts b/packages/jsts/src/rules/S4123/unit.test.ts index 150337f46f..a3171b68da 100644 --- a/packages/jsts/src/rules/S4123/unit.test.ts +++ b/packages/jsts/src/rules/S4123/unit.test.ts @@ -16,35 +16,36 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4123', () => { - const ruleTester = new RuleTester(); - ruleTester.run('await should only be used with promises.', rule, { - valid: [ - { - code: ` + it('S4123', () => { + const ruleTester = new RuleTester(); + ruleTester.run('await should only be used with promises.', rule, { + valid: [ + { + code: ` async function foo() { await ({then() { }}); } `, - }, - { - code: ` + }, + { + code: ` async function foo() { await Promise.resolve(42); } `, - }, - { - code: ` + }, + { + code: ` async function foo(p: PromiseLike) { await p; } `, - }, - { - code: ` + }, + { + code: ` class MyPromiseLike implements PromiseLike { then(){} } @@ -52,9 +53,9 @@ describe('S4123', () => { await new MyPromiseLike(); } `, - }, - { - code: ` + }, + { + code: ` class MyPromiseLike implements PromiseLike { then(){} } @@ -65,9 +66,9 @@ describe('S4123', () => { await new MyPromiseLike2(); } `, - }, - { - code: ` + }, + { + code: ` class MyPromise implements Promise { then(){} } @@ -75,9 +76,9 @@ describe('S4123', () => { await new MyPromise(); } `, - }, - { - code: ` + }, + { + code: ` interface Thenable { then: () => T } @@ -90,17 +91,17 @@ describe('S4123', () => { await new MyThenable(); } `, - }, - { - code: ` + }, + { + code: ` import { NotExisting } from "invalid"; async function foo() { await new NotExisting(); } `, - }, - { - code: ` + }, + { + code: ` function returnNumber(): number | Promise { return 1 } @@ -108,9 +109,9 @@ describe('S4123', () => { await returnNumber(); } `, - }, - { - code: ` + }, + { + code: ` interface MyQuery extends Pick, keyof Promise> { toQuery(): string; } @@ -119,16 +120,16 @@ describe('S4123', () => { console.log(result); } `, - }, - { - code: ` + }, + { + code: ` async function foo(x: unknown) { await x; } `, - }, - { - code: ` + }, + { + code: ` export class NoErrorThrownError extends Error {}; export class TestUtils { public static getError = async ( @@ -143,101 +144,101 @@ describe('S4123', () => { }; } `, - }, - { - code: ` + }, + { + code: ` class Foo { then: Promise; } function qux(): Foo {} const baz = await qux();`, - }, - { - code: ` + }, + { + code: ` async function foo() { await bar(); } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` async function foo() { let arr = [1, 2, 3]; await arr; } `, - errors: [ - { - message: "Refactor this redundant 'await' on a non-promise.", - line: 4, - endLine: 4, - column: 9, - endColumn: 18, - }, - ], - }, - { - code: ` + errors: [ + { + message: "Refactor this redundant 'await' on a non-promise.", + line: 4, + endLine: 4, + column: 9, + endColumn: 18, + }, + ], + }, + { + code: ` async function foo() { let x: number = 1; await x; } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` async function foo() { await 1; } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` async function foo() { await {else: 42}; } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` async function foo() { await {then: 42}; } `, - errors: 1, - }, - ], - }); + errors: 1, + }, + ], + }); - const ruleTesterWithNoFullTypeInfo = new RuleTester(); + const ruleTesterWithNoFullTypeInfo = new RuleTester(); - ruleTesterWithNoFullTypeInfo.run('await should only be used with promises.', rule, { - valid: [ - { - code: ` + ruleTesterWithNoFullTypeInfo.run('await should only be used with promises.', rule, { + valid: [ + { + code: ` async function bar() { return 42; } async function foo() { await bar(); } `, - }, - ], - invalid: [], - }); + }, + ], + invalid: [], + }); - const javaScriptRuleTester = new RuleTester(); - javaScriptRuleTester.run( - 'await should only be used with promises: ignore function calls for functions with JSdoc', - rule, - { - valid: [ - { - code: ` + const javaScriptRuleTester = new RuleTester(); + javaScriptRuleTester.run( + 'await should only be used with promises: ignore function calls for functions with JSdoc', + rule, + { + valid: [ + { + code: ` async function foo () { await bar() // Compliant: ignored because of JSDoc } @@ -247,9 +248,9 @@ async function foo () { async function bar () { return 5; }`, - }, - { - code: ` + }, + { + code: ` async function foo () { await bar() // Compliant: ignored because of JSDoc } @@ -259,9 +260,9 @@ async function foo () { async function bar () { return Promise.resolve(5); }`, - }, - { - code: ` + }, + { + code: ` async function foo () { await bar.baz() // Compliant: ignored because of JSDoc } @@ -274,21 +275,21 @@ const bar = { return Promise.resolve(5); } }`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` async function foo () { await bar() // Noncompliant } function bar () { return 5; }`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` async function foo () { await bar() // Noncompliant } @@ -298,9 +299,10 @@ async function foo () { function bar () { return 5; }`, - errors: 1, - }, - ], - }, - ); + errors: 1, + }, + ], + }, + ); + }); }); diff --git a/packages/jsts/src/rules/S4138/unit.test.ts b/packages/jsts/src/rules/S4138/unit.test.ts index 23b24ed564..bc561b66f5 100644 --- a/packages/jsts/src/rules/S4138/unit.test.ts +++ b/packages/jsts/src/rules/S4138/unit.test.ts @@ -16,155 +16,156 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4138', () => { - const ruleTester = new RuleTester(); + it('S4138', () => { + const ruleTester = new RuleTester(); - ruleTester.run(`Decorated rule should provide suggestion`, rule, { - valid: [ - { - code: `for (let i = 0; i < arr.length; ++i) console.log(i, arr[i]);`, - }, - ], - invalid: [ - { - code: `for (let i = 0; i < arr.length; ++i) console.log(arr[i]);`, - errors: [ - { - messageId: 'preferForOf', - suggestions: [ - { - desc: `Replace with "for of" loop`, - output: `for (const element of arr) console.log(element);`, - }, - ], - }, - ], - }, - { - code: `for (let i = 0; i < arr.length; ++i) { console.log(arr[i]); }`, - errors: [ - { - messageId: 'preferForOf', - suggestions: [ - { - desc: `Replace with "for of" loop`, - output: `for (const element of arr) { console.log(element); }`, - }, - ], - }, - ], - }, - { - code: `for (let i = 0; i < arr.length; ++i) { console.log(arr[i]); } ++arr[i];`, - errors: [ - { - messageId: 'preferForOf', - suggestions: [ - { - desc: `Replace with "for of" loop`, - output: `for (const element of arr) { console.log(element); } ++arr[i];`, - }, - ], - }, - ], - }, - { - code: `++arr[i]; for (let i = 0; i < arr.length; ++i) { console.log(arr[i]); }`, - errors: [ - { - messageId: 'preferForOf', - suggestions: [ - { - desc: `Replace with "for of" loop`, - output: `++arr[i]; for (const element of arr) { console.log(element); }`, - }, - ], - }, - ], - }, - { - code: `for (let i = 0; i < arr.length; ++i) console.log(arr[i] + arr[i]);`, - errors: [ - { - messageId: 'preferForOf', - suggestions: [ - { - desc: `Replace with "for of" loop`, - output: `for (const element of arr) console.log(element + element);`, - }, - ], - }, - ], - }, - { - code: ` + ruleTester.run(`Decorated rule should provide suggestion`, rule, { + valid: [ + { + code: `for (let i = 0; i < arr.length; ++i) console.log(i, arr[i]);`, + }, + ], + invalid: [ + { + code: `for (let i = 0; i < arr.length; ++i) console.log(arr[i]);`, + errors: [ + { + messageId: 'preferForOf', + suggestions: [ + { + desc: `Replace with "for of" loop`, + output: `for (const element of arr) console.log(element);`, + }, + ], + }, + ], + }, + { + code: `for (let i = 0; i < arr.length; ++i) { console.log(arr[i]); }`, + errors: [ + { + messageId: 'preferForOf', + suggestions: [ + { + desc: `Replace with "for of" loop`, + output: `for (const element of arr) { console.log(element); }`, + }, + ], + }, + ], + }, + { + code: `for (let i = 0; i < arr.length; ++i) { console.log(arr[i]); } ++arr[i];`, + errors: [ + { + messageId: 'preferForOf', + suggestions: [ + { + desc: `Replace with "for of" loop`, + output: `for (const element of arr) { console.log(element); } ++arr[i];`, + }, + ], + }, + ], + }, + { + code: `++arr[i]; for (let i = 0; i < arr.length; ++i) { console.log(arr[i]); }`, + errors: [ + { + messageId: 'preferForOf', + suggestions: [ + { + desc: `Replace with "for of" loop`, + output: `++arr[i]; for (const element of arr) { console.log(element); }`, + }, + ], + }, + ], + }, + { + code: `for (let i = 0; i < arr.length; ++i) console.log(arr[i] + arr[i]);`, + errors: [ + { + messageId: 'preferForOf', + suggestions: [ + { + desc: `Replace with "for of" loop`, + output: `for (const element of arr) console.log(element + element);`, + }, + ], + }, + ], + }, + { + code: ` for (let i = 0; i < arr.length; ++i) { if (foo() < arr[i]) { console.log(arr[i] * 2); } }`, - errors: [ - { - messageId: 'preferForOf', - suggestions: [ - { - desc: `Replace with "for of" loop`, - output: ` + errors: [ + { + messageId: 'preferForOf', + suggestions: [ + { + desc: `Replace with "for of" loop`, + output: ` for (const element of arr) { if (foo() < element) { console.log(element * 2); } }`, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` for (let i = 0; i < arr.length; ++i) { console.log(arr[i]); for (let j = 0; j < arr.length; ++j) { console.log(arr[j]); } }`, - errors: [ - { - messageId: 'preferForOf', - suggestions: [ - { - desc: `Replace with "for of" loop`, - output: ` + errors: [ + { + messageId: 'preferForOf', + suggestions: [ + { + desc: `Replace with "for of" loop`, + output: ` for (const element of arr) { console.log(element); for (let j = 0; j < arr.length; ++j) { console.log(arr[j]); } }`, - }, - ], - }, - { - messageId: 'preferForOf', - suggestions: [ - { - desc: `Replace with "for of" loop`, - output: ` + }, + ], + }, + { + messageId: 'preferForOf', + suggestions: [ + { + desc: `Replace with "for of" loop`, + output: ` for (let i = 0; i < arr.length; ++i) { console.log(arr[i]); for (const element of arr) { console.log(element); } }`, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` for (let i = 0; i < arr.length; ++i) { console.log(arr[i]); for (let i = 0; i < arr.length; ++i) { @@ -172,13 +173,13 @@ for (let i = 0; i < arr.length; ++i) { } } console.log(arr[i]);`, - errors: [ - { - messageId: 'preferForOf', - suggestions: [ - { - desc: `Replace with "for of" loop`, - output: ` + errors: [ + { + messageId: 'preferForOf', + suggestions: [ + { + desc: `Replace with "for of" loop`, + output: ` for (const element of arr) { console.log(element); for (let i = 0; i < arr.length; ++i) { @@ -186,15 +187,15 @@ for (const element of arr) { } } console.log(arr[i]);`, - }, - ], - }, - { - messageId: 'preferForOf', - suggestions: [ - { - desc: `Replace with "for of" loop`, - output: ` + }, + ], + }, + { + messageId: 'preferForOf', + suggestions: [ + { + desc: `Replace with "for of" loop`, + output: ` for (let i = 0; i < arr.length; ++i) { console.log(arr[i]); for (const element of arr) { @@ -202,29 +203,30 @@ for (let i = 0; i < arr.length; ++i) { } } console.log(arr[i]);`, - }, - ], - }, - ], - }, - { - code: `for (let i = 0; i < arr.length; ++i) console.log(arr[element])`, - errors: [ - { - messageId: 'preferForOf', - suggestions: [], - }, - ], - }, - { - code: `for (let i = 0; i < arr.length; ++i) { console.log(arr[element]) }`, - errors: [ - { - messageId: 'preferForOf', - suggestions: [], - }, - ], - }, - ], + }, + ], + }, + ], + }, + { + code: `for (let i = 0; i < arr.length; ++i) console.log(arr[element])`, + errors: [ + { + messageId: 'preferForOf', + suggestions: [], + }, + ], + }, + { + code: `for (let i = 0; i < arr.length; ++i) { console.log(arr[element]) }`, + errors: [ + { + messageId: 'preferForOf', + suggestions: [], + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4139/unit.test.ts b/packages/jsts/src/rules/S4139/unit.test.ts index 199ca96aa9..f929798724 100644 --- a/packages/jsts/src/rules/S4139/unit.test.ts +++ b/packages/jsts/src/rules/S4139/unit.test.ts @@ -16,129 +16,131 @@ */ import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4139', () => { - const ruleTesterJs = new DefaultParserRuleTester(); - ruleTesterJs.run('"for in" should not be used with iterables [js]', rule, { - valid: [ - { - code: ` + it('S4139', () => { + const ruleTesterJs = new DefaultParserRuleTester(); + ruleTesterJs.run('"for in" should not be used with iterables [js]', rule, { + valid: [ + { + code: ` const array = [1, 2, 3]; for (let value in array) console.log(value); // not reported if type information is missing`, - }, - { - code: ` + }, + { + code: ` for (const x of [3, 4, 5]) { console.log(x); } `, - }, - ], - invalid: [], - }); + }, + ], + invalid: [], + }); - const ruleTesterTs = new RuleTester(); - ruleTesterTs.run('"for in" should not be used with iterables [ts]', rule, { - valid: [ - { - code: ` + const ruleTesterTs = new RuleTester(); + ruleTesterTs.run('"for in" should not be used with iterables [ts]', rule, { + valid: [ + { + code: ` const object = { fst: 1, snd: 2 }; for (let value in object) console.log(value);`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const array = [1, 2, 3]; for (let value in array) console.log(value);`, - errors: [ - { - message: `Use \"for...of\" to iterate over this \"Array\".`, - line: 3, - column: 9, - endLine: 3, - endColumn: 12, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Use \"for...of\" to iterate over this \"Array\".`, + line: 3, + column: 9, + endLine: 3, + endColumn: 12, + }, + ], + }, + { + code: ` const array = new Int8Array(5); for (let value in array) console.log(value);`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const set = new Set([1, 2, 3, 4, 5]); for (let value in set) console.log(value);`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const map = new Map(); map.set('zero', 0); for (let value in map) console.log(value);`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const string = 'Hello'; for (let value in string) console.log(value);`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const string = new String('Hello'); for (let value in string) console.log(value);`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` for (const x in [3, 4, 5]) { console.log(x); } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const z = [3, 4, 5]; for (const x in z) { console.log(x); } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const fn = (arr: number[]) => { for (const x in arr) { console.log(x); } }; `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const fn = (arr: number[] | string[]) => { for (const x in arr) { console.log(x); } }; `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const fn = (arr: T) => { for (const x in arr) { console.log(x); } }; `, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4143/unit.test.ts b/packages/jsts/src/rules/S4143/unit.test.ts index f4f54de8cc..ee6728c97b 100644 --- a/packages/jsts/src/rules/S4143/unit.test.ts +++ b/packages/jsts/src/rules/S4143/unit.test.ts @@ -16,68 +16,69 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4143', () => { - const ruleTester = new RuleTester(); + it('S4143', () => { + const ruleTester = new RuleTester(); - ruleTester.run('no-element-overwrite', rule, { - valid: [ - { - code: ` + ruleTester.run('no-element-overwrite', rule, { + valid: [ + { + code: ` fruits[1] = "banana"; fruits[2] = "apple";`, - }, - { - code: ` + }, + { + code: ` fruits[1] = "banana"; vegerables[1] = "tomato";`, - }, - { - code: ` + }, + { + code: ` fruits[1] = "banana"; console.log("Hello"); fruits[1] = "apple"; // FN`, - }, - { - code: ` + }, + { + code: ` fruits[1] = "banana"; foo(fruits); fruits[1] = "apple";`, - }, - { - code: ` + }, + { + code: ` fruits[1] = "banana"; if (cond) { fruits[1] = "apple"; }`, - }, - { - code: ` + }, + { + code: ` fruits[2] = "orange"; fruits[2] = fruits[2] + ";";`, - }, - { - code: ` + }, + { + code: ` this.fruits[2] = "orange"; this.fruits[2] = foo(this.fruits) + ";";`, - }, - { - code: ` + }, + { + code: ` this.fruits[2] = "orange"; this.fruits[2] = foo(this.bar, this.fruits);`, - }, - { - code: ` + }, + { + code: ` function anotherCollection() { var x = [1,], y = [1, ]; x[1] = 3; y[1] = x[1]; x[1] = 43; // Compliant }`, - }, - { - code: ` + }, + { + code: ` function indexChanges() { var nums = []; var i = 1; @@ -88,145 +89,145 @@ describe('S4143', () => { i += 1; nums[i] = 2; }`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` fruits[1] = "banana"; fruits[1] = "apple";`, - errors: [ - { - messageId: 'verifyIntendedIndex', - data: { - index: 1, - line: 2, + errors: [ + { + messageId: 'verifyIntendedIndex', + data: { + index: 1, + line: 2, + }, + line: 3, + column: 7, + endColumn: 26, }, - line: 3, - column: 7, - endColumn: 26, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` fruits[1] = "banana"; //^^^^^^^^^^^^^^^^^^^^> fruits[1] = "apple"; //^^^^^^^^^^^^^^^^^^^`, - options: ['sonar-runtime'], - errors: [ - { - messageId: 'sonarRuntime', - data: { - index: 1, - line: 2, - sonarRuntimeData: JSON.stringify({ - message: `Verify this is the index that was intended; "1" was already set on line 2.`, - secondaryLocations: [ - { message: 'Original value', column: 6, line: 2, endColumn: 26, endLine: 2 }, - ], - }), + options: ['sonar-runtime'], + errors: [ + { + messageId: 'sonarRuntime', + data: { + index: 1, + line: 2, + sonarRuntimeData: JSON.stringify({ + message: `Verify this is the index that was intended; "1" was already set on line 2.`, + secondaryLocations: [ + { message: 'Original value', column: 6, line: 2, endColumn: 26, endLine: 2 }, + ], + }), + }, }, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` fruits[1] = "banana"; fruits[2] = "orange"; fruits[1] = "apple";`, - errors: [ - { - messageId: 'verifyIntendedIndex', - data: { - index: 1, - line: 2, + errors: [ + { + messageId: 'verifyIntendedIndex', + data: { + index: 1, + line: 2, + }, }, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` this.fruits[1] = "banana"; this.fruits[1] = "apple";`, - errors: [ - { - messageId: 'verifyIntendedIndex', - data: { - index: 1, - line: 2, + errors: [ + { + messageId: 'verifyIntendedIndex', + data: { + index: 1, + line: 2, + }, }, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` this.fruits[1] = "banana"; this.fruits[1] = foo(this.bar);`, - errors: [ - { - messageId: 'verifyIntendedIndex', - data: { - index: 1, - line: 2, + errors: [ + { + messageId: 'verifyIntendedIndex', + data: { + index: 1, + line: 2, + }, }, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` for (var i = 0; i < 10; i++) { fruits[i] = "melon"; fruits[i] = "pear"; fruits[i++] = "another"; }`, - errors: [ - { - messageId: 'verifyIntendedIndex', - data: { - index: 'i', - line: 3, + errors: [ + { + messageId: 'verifyIntendedIndex', + data: { + index: 'i', + line: 3, + }, }, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` myMap.set("key", 1); myMap.set("key", 2); myMap.clear(); myMap.set("key", 1);`, - errors: [ - { - messageId: 'verifyIntendedIndex', - data: { - index: 'key', - line: 2, + errors: [ + { + messageId: 'verifyIntendedIndex', + data: { + index: 'key', + line: 2, + }, }, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` mySet.add(1); mySet.add(2); mySet.add(3); mySet.add(2); mySet.clear(); mySet.add(2);`, - errors: [ - { - messageId: 'verifyIntendedIndex', - data: { - index: 2, - line: 3, + errors: [ + { + messageId: 'verifyIntendedIndex', + data: { + index: 2, + line: 3, + }, }, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` function switchTest(kind) { var result = []; switch (kind) { @@ -240,37 +241,38 @@ describe('S4143', () => { break; } }`, - errors: [ - { - messageId: 'verifyIntendedIndex', - data: { - index: 1, - line: 6, + errors: [ + { + messageId: 'verifyIntendedIndex', + data: { + index: 1, + line: 6, + }, }, - }, - { - messageId: 'verifyIntendedIndex', - data: { - index: 2, - line: 10, + { + messageId: 'verifyIntendedIndex', + data: { + index: 2, + line: 10, + }, }, - }, - ], - }, - { - code: ` + ], + }, + { + code: ` fruits[''] = "banana"; fruits[''] = "apple";`, - errors: [ - { - messageId: 'verifyIntendedIndex', - data: { - index: '', - line: 2, + errors: [ + { + messageId: 'verifyIntendedIndex', + data: { + index: '', + line: 2, + }, }, - }, - ], - }, - ], + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4144/unit.test.ts b/packages/jsts/src/rules/S4144/unit.test.ts index fb368e58b4..3152bbd1d7 100644 --- a/packages/jsts/src/rules/S4144/unit.test.ts +++ b/packages/jsts/src/rules/S4144/unit.test.ts @@ -17,16 +17,17 @@ import { rule } from './rule.js'; import { expandMessage, IssueLocation } from '../helpers/index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4144', () => { - const ruleTester = new RuleTester(); + it('S4144', () => { + const ruleTester = new RuleTester(); - ruleTester.run('no-identical-functions', rule, { - valid: [ - { - // different body - code: ` + ruleTester.run('no-identical-functions', rule, { + valid: [ + { + // different body + code: ` function foo() { console.log("Hello"); console.log("World"); @@ -39,10 +40,10 @@ describe('S4144', () => { } return 42; }`, - }, - { - // few lines - code: ` + }, + { + // few lines + code: ` function foo() { console.log("Hello"); return 42; @@ -52,9 +53,9 @@ describe('S4144', () => { console.log("Hello"); return 42; }`, - }, - { - code: ` + }, + { + code: ` let foo = (a, b) => { [ a, @@ -69,9 +70,9 @@ describe('S4144', () => { ] ) `, - }, - { - code: ` + }, + { + code: ` class Foo { foo() { console.log("Hello"); @@ -84,13 +85,13 @@ describe('S4144', () => { return 42; } }`, - options: [4], - }, - ], - invalid: [ - { - // basic case - code: ` + options: [4], + }, + ], + invalid: [ + { + // basic case + code: ` function foo() { console.log("Hello"); console.log("World"); @@ -102,11 +103,11 @@ describe('S4144', () => { console.log("World"); return 42; }`, - errors: [message(2, 8)], - }, - { - // different kinds of functions - code: ` + errors: [message(2, 8)], + }, + { + // different kinds of functions + code: ` function foo() { console.log("Hello"); console.log("World"); @@ -162,56 +163,56 @@ describe('S4144', () => { console.log("World"); return 42; }`, - errors: [ - // prettier-ignore - message(2, 8), - message(2, 14), - { - message: - 'Update this function so that its implementation is not identical to the one on line 2.', - line: 21, - column: 9, - endColumn: 20, - }, // constructor - { - message: - 'Update this function so that its implementation is not identical to the one on line 2.', - line: 27, - column: 9, - endColumn: 15, - }, // method - { - message: - 'Update this function so that its implementation is not identical to the one on line 2.', - line: 33, - column: 13, - endColumn: 19, - }, // setter - { - message: - 'Update this function so that its implementation is not identical to the one on line 2.', - line: 39, - column: 13, - endColumn: 19, - }, // getter - { - message: - 'Update this function so that its implementation is not identical to the one on line 2.', - line: 46, - column: 22, - endColumn: 35, - }, // async declaration - { - message: - 'Update this function so that its implementation is not identical to the one on line 2.', - line: 52, - column: 35, - endColumn: 43, - }, // async expression - ], - }, - { - code: ` + errors: [ + // prettier-ignore + message(2, 8), + message(2, 14), + { + message: + 'Update this function so that its implementation is not identical to the one on line 2.', + line: 21, + column: 9, + endColumn: 20, + }, // constructor + { + message: + 'Update this function so that its implementation is not identical to the one on line 2.', + line: 27, + column: 9, + endColumn: 15, + }, // method + { + message: + 'Update this function so that its implementation is not identical to the one on line 2.', + line: 33, + column: 13, + endColumn: 19, + }, // setter + { + message: + 'Update this function so that its implementation is not identical to the one on line 2.', + line: 39, + column: 13, + endColumn: 19, + }, // getter + { + message: + 'Update this function so that its implementation is not identical to the one on line 2.', + line: 46, + column: 22, + endColumn: 35, + }, // async declaration + { + message: + 'Update this function so that its implementation is not identical to the one on line 2.', + line: 52, + column: 35, + endColumn: 43, + }, // async expression + ], + }, + { + code: ` function foo(a, b) { a += b; b -= a; return { b @@ -223,15 +224,21 @@ describe('S4144', () => { }; } `, - options: [3, 'sonar-runtime'], - errors: [ - encodedMessage(2, 7, [ - { message: 'Original implementation', column: 17, line: 2, endColumn: 20, endLine: 2 }, - ]), - ], - }, - { - code: ` + options: [3, 'sonar-runtime'], + errors: [ + encodedMessage(2, 7, [ + { + message: 'Original implementation', + column: 17, + line: 2, + endColumn: 20, + endLine: 2, + }, + ]), + ], + }, + { + code: ` function foo(a) { try { return a; @@ -247,15 +254,21 @@ describe('S4144', () => { } } `, - options: [3, 'sonar-runtime'], - errors: [ - encodedMessage(2, 9, [ - { message: 'Original implementation', column: 17, line: 2, endColumn: 20, endLine: 2 }, - ]), - ], - }, - { - code: ` + options: [3, 'sonar-runtime'], + errors: [ + encodedMessage(2, 9, [ + { + message: 'Original implementation', + column: 17, + line: 2, + endColumn: 20, + endLine: 2, + }, + ]), + ], + }, + { + code: ` class Foo { foo() { console.log("Hello"); @@ -269,10 +282,10 @@ describe('S4144', () => { } } `, - errors: [message(3, 8)], - }, - { - code: ` + errors: [message(3, 8)], + }, + { + code: ` const foo = () => { console.log("Hello"); console.log("World"); @@ -284,40 +297,41 @@ describe('S4144', () => { return 42; }; `, - errors: [message(2, 7)], - }, - ], - }); + errors: [message(2, 7)], + }, + ], + }); - function message(originalLine: number, duplicationLine: number) { - return { - message: expandMessage( - 'Update this function so that its implementation is not identical to the one on line {{line}}.', - { + function message(originalLine: number, duplicationLine: number) { + return { + message: expandMessage( + 'Update this function so that its implementation is not identical to the one on line {{line}}.', + { + line: originalLine, + }, + ), + line: duplicationLine, + endLine: duplicationLine, + }; + } + + function encodedMessage( + originalLine: number, + duplicationLine: number, + secondaries: IssueLocation[], + ) { + return { + messageId: 'sonarRuntime', + data: { line: originalLine, + sonarRuntimeData: JSON.stringify({ + message: `Update this function so that its implementation is not identical to the one on line ${originalLine}.`, + secondaryLocations: secondaries, + }), }, - ), - line: duplicationLine, - endLine: duplicationLine, - }; - } - - function encodedMessage( - originalLine: number, - duplicationLine: number, - secondaries: IssueLocation[], - ) { - return { - messageId: 'sonarRuntime', - data: { - line: originalLine, - sonarRuntimeData: JSON.stringify({ - message: `Update this function so that its implementation is not identical to the one on line ${originalLine}.`, - secondaryLocations: secondaries, - }), - }, - line: duplicationLine, - endLine: duplicationLine, - }; - } + line: duplicationLine, + endLine: duplicationLine, + }; + } + }); }); diff --git a/packages/jsts/src/rules/S4158/unit.test.ts b/packages/jsts/src/rules/S4158/unit.test.ts index 76474bfab6..12f7bd2126 100644 --- a/packages/jsts/src/rules/S4158/unit.test.ts +++ b/packages/jsts/src/rules/S4158/unit.test.ts @@ -16,49 +16,50 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4158', () => { - const ruleTester = new RuleTester(); + it('S4158', () => { + const ruleTester = new RuleTester(); - ruleTester.run('Empty collections should not be accessed or iterated', rule, { - valid: [ - { - code: `function okForNotEmptyInit() { + ruleTester.run('Empty collections should not be accessed or iterated', rule, { + valid: [ + { + code: `function okForNotEmptyInit() { const nonEmptyArray = [1, 2, 3]; foo(nonEmptyArray[2]); // OK nonEmptyArray.forEach(item => console.log()); // OK for (const _ of nonEmptyArray) { console.log(); } // OK }`, - }, - { - code: `function okLatelyWritten() { + }, + { + code: `function okLatelyWritten() { const okLatelyWritten: number[] = []; okLatelyWritten.push(1); okLatelyWritten.forEach(item => console.log()); // OK }`, - }, - { - code: `function testCollectionContructors(){ + }, + { + code: `function testCollectionContructors(){ const notEmptyarrayConstructor = new Array(1, 2, 3); notEmptyarrayConstructor.forEach(item => console.log()); // Ok }`, - }, - { - code: `function parametersAreIgnore(parameterArray: number[]) { + }, + { + code: `function parametersAreIgnore(parameterArray: number[]) { foo(parameterArray[1]); }`, - }, - { - code: `class MyClass { + }, + { + code: `class MyClass { myArray: string [] = []; propertiesAreIgnored() { foo(this.myArray[1]); // OK } }`, - }, - { - code: `function arrayUsedAsArgument() { + }, + { + code: `function arrayUsedAsArgument() { const array: number[] = []; foo(array); const copy = new Array(...array); @@ -67,9 +68,9 @@ describe('S4158', () => { return copy; }`, - }, - { - code: `function reassignment() { + }, + { + code: `function reassignment() { let overwrittenArray = []; const otherArray = [1,2,3,4]; overwrittenArray = otherArray; @@ -83,9 +84,9 @@ describe('S4158', () => { foo((n: number) => arrayWrittenInsideArrow2 = otherArray); foo(arrayWrittenInsideArrow2[1]); // OK }`, - }, - { - code: `// Interface Declaration + }, + { + code: `// Interface Declaration interface Array { equals(array: Array): boolean // OK, symbol Array is an interface declaration } @@ -96,9 +97,9 @@ describe('S4158', () => { function isMyArrayTypeAlias(value: MyArrayTypeAlias | number): value is MyArrayTypeAlias { return !!(value as any).length; }`, - }, - { - code: `function arrayUsedInPropertyDeclaration() { + }, + { + code: `function arrayUsedInPropertyDeclaration() { const emptyArray: number[] = []; return { a: emptyArray // OK, emptyArray is used in a property declaration @@ -109,9 +110,9 @@ describe('S4158', () => { const emptyArray: number[] = []; return emptyArray; // OK, emptyArray is used in a return statement }`, - }, - { - code: `function writeOnAliasVariable() { + }, + { + code: `function writeOnAliasVariable() { const reassignedArray: number[] = []; const aliasArray = reassignedArray; aliasArray.push(1); @@ -119,33 +120,33 @@ describe('S4158', () => { foo(aliasArray[0]); // OK foo(reassignedArray[0]); // OK }`, - }, - { - code: `function assignmentEmptyArray() { + }, + { + code: `function assignmentEmptyArray() { const assignmentEmptyArray: number[] = []; assignmentEmptyArray[1] = 42; // ok }`, - }, - { - code: `function arrayNotInitialized() { + }, + { + code: `function arrayNotInitialized() { let notInitializedArray!: number[]; foo(notInitializedArray[0]); // Not reported }`, - }, - { - code: `function arrayInitializedByFunctionCall(init: () => number[]) { + }, + { + code: `function arrayInitializedByFunctionCall(init: () => number[]) { const externalInitializedArray: number[] = init(); foo(externalInitializedArray[0]); // OK }`, - }, - { - code: `function arrayUsedInORExpression(otherArray: number[]) { + }, + { + code: `function arrayUsedInORExpression(otherArray: number[]) { const emptyArray: number[] = []; console.log(otherArray || emptyArray); // OK used in OR expression }`, - }, - { - code: `function writeWithTernaryOperator(flag: boolean) { + }, + { + code: `function writeWithTernaryOperator(flag: boolean) { const potentiallyNonEmptyArray1 : number [] = []; const potentiallyNonEmptyArray2: number[] = []; (flag ? potentiallyNonEmptyArray1 : potentiallyNonEmptyArray2).push(1); @@ -153,20 +154,20 @@ describe('S4158', () => { foo(potentiallyNonEmptyArray1[0]); // OK foo(potentiallyNonEmptyArray2[0]); // OK }`, - }, - { - code: `function destructuringAssignmentEmptyArray() { + }, + { + code: `function destructuringAssignmentEmptyArray() { const destructuringAssignmentEmptyArray: number[] = []; [ , destructuringAssignmentEmptyArray[1]] = [42, 42]; // ok foo(destructuringAssignmentEmptyArray[1]); }`, - }, - { - code: `import { IMPORTED_ARRAY } from "./dep"; + }, + { + code: `import { IMPORTED_ARRAY } from "./dep"; foo(IMPORTED_ARRAY[1]); // OK`, - }, - { - code: `function indexWriteInInnerFunction() { + }, + { + code: `function indexWriteInInnerFunction() { let a = []; innerFunction(); a.indexOf('x'); @@ -175,9 +176,9 @@ describe('S4158', () => { a[0] = 42; } }`, - }, - { - code: `function overwritingCollectionInInnerFunction() { + }, + { + code: `function overwritingCollectionInInnerFunction() { let a = []; innerFunction(); a.indexOf('x'); @@ -186,9 +187,9 @@ describe('S4158', () => { a = unknownFunction(); } }`, - }, - { - code: ` + }, + { + code: ` // Since issue-1974, order of occurrences is ignored, and parameters // are considered potentially nonempty, thus all reading occurrences // are considered meaningful. @@ -197,92 +198,92 @@ describe('S4158', () => { parameterArray = []; foo(parameterArray[1]); // FN introduced with issue-1974 to avoid FPs. }`, - }, - { - code: ` + }, + { + code: ` // Analogous to parametersAreIgnored import {c} from 'nonemptyCollections'; c = []; console.log(c[0]); // FN introduced with issue-1974 to avoid FPs `, - }, - { - code: ` + }, + { + code: ` function argumentsAreNonempty() { console.log(arguments[0]); }`, - }, - ], - invalid: [ - { - code: `const array : number[] = []; + }, + ], + invalid: [ + { + code: `const array : number[] = []; export function testElementAccessRead() { console.log(array[2]); }`, - errors: [ - { - messageId: 'reviewUsageOfIdentifier', - data: { - identifierName: 'array', + errors: [ + { + messageId: 'reviewUsageOfIdentifier', + data: { + identifierName: 'array', + }, + line: 3, + endLine: 3, + column: 29, + endColumn: 34, }, - line: 3, - endLine: 3, - column: 29, - endColumn: 34, - }, - ], - }, - { - code: `function testAccessorMethodsRead(otherArray: number[]) { + ], + }, + { + code: `function testAccessorMethodsRead(otherArray: number[]) { const initialArray: number[] = []; return initialArray.concat(otherArray); // Noncompliant }`, - errors: [ - { - messageId: 'reviewUsageOfIdentifier', - data: { - identifierName: 'initialArray', + errors: [ + { + messageId: 'reviewUsageOfIdentifier', + data: { + identifierName: 'initialArray', + }, }, - }, - ], - }, - { - code: `const array : number[] = []; + ], + }, + { + code: `const array : number[] = []; export function testElementAccessRead() { console.log(array[2]); console.log(array[2]); console.log(array[2]); console.log(array[2]); }`, - errors: [ - { - messageId: 'reviewUsageOfIdentifier', - data: { - identifierName: 'array', + errors: [ + { + messageId: 'reviewUsageOfIdentifier', + data: { + identifierName: 'array', + }, }, - }, - { - messageId: 'reviewUsageOfIdentifier', - data: { - identifierName: 'array', + { + messageId: 'reviewUsageOfIdentifier', + data: { + identifierName: 'array', + }, }, - }, - { - messageId: 'reviewUsageOfIdentifier', - data: { - identifierName: 'array', + { + messageId: 'reviewUsageOfIdentifier', + data: { + identifierName: 'array', + }, }, - }, - { - messageId: 'reviewUsageOfIdentifier', - data: { - identifierName: 'array', + { + messageId: 'reviewUsageOfIdentifier', + data: { + identifierName: 'array', + }, }, - }, - ], - }, - { - code: `const array : number[] = []; + ], + }, + { + code: `const array : number[] = []; function testLoopRead() { for (const _ of array) { // Noncompliant } @@ -294,35 +295,35 @@ describe('S4158', () => { array[Symbol.iterator](); // Noncompliant } `, - errors: [ - { - messageId: 'reviewUsageOfIdentifier', - data: { - identifierName: 'array', + errors: [ + { + messageId: 'reviewUsageOfIdentifier', + data: { + identifierName: 'array', + }, }, - }, - { - messageId: 'reviewUsageOfIdentifier', - data: { - identifierName: 'array', + { + messageId: 'reviewUsageOfIdentifier', + data: { + identifierName: 'array', + }, }, - }, - { - messageId: 'reviewUsageOfIdentifier', - data: { - identifierName: 'array', + { + messageId: 'reviewUsageOfIdentifier', + data: { + identifierName: 'array', + }, }, - }, - { - messageId: 'reviewUsageOfIdentifier', - data: { - identifierName: 'array', + { + messageId: 'reviewUsageOfIdentifier', + data: { + identifierName: 'array', + }, }, - }, - ], - }, - { - code: `function testCollectionContructors(){ + ], + }, + { + code: `function testCollectionContructors(){ const arrayConstructor = new Array(); arrayConstructor.forEach(item => console.log()); // Noncompliant @@ -335,88 +336,89 @@ describe('S4158', () => { const mySet = new Set(); mySet.has(1); // Noncompliant }`, - errors: [ - { - messageId: 'reviewUsageOfIdentifier', - data: { - identifierName: 'arrayConstructor', + errors: [ + { + messageId: 'reviewUsageOfIdentifier', + data: { + identifierName: 'arrayConstructor', + }, }, - }, - { - messageId: 'reviewUsageOfIdentifier', - data: { - identifierName: 'arrayWithoutNew', + { + messageId: 'reviewUsageOfIdentifier', + data: { + identifierName: 'arrayWithoutNew', + }, }, - }, - { - messageId: 'reviewUsageOfIdentifier', - data: { - identifierName: 'myMap', + { + messageId: 'reviewUsageOfIdentifier', + data: { + identifierName: 'myMap', + }, }, - }, - { - messageId: 'reviewUsageOfIdentifier', - data: { - identifierName: 'mySet', + { + messageId: 'reviewUsageOfIdentifier', + data: { + identifierName: 'mySet', + }, }, - }, - ], - }, - { - code: `function compoundAssignmentEmptyArray() { + ], + }, + { + code: `function compoundAssignmentEmptyArray() { const compoundAssignmentEmptyArray: number[] = []; compoundAssignmentEmptyArray[1] += 42; // Noncompliant }`, - errors: [ - { - messageId: 'reviewUsageOfIdentifier', - data: { - identifierName: 'compoundAssignmentEmptyArray', + errors: [ + { + messageId: 'reviewUsageOfIdentifier', + data: { + identifierName: 'compoundAssignmentEmptyArray', + }, }, - }, - ], - }, - { - code: `function elementAccessWithoutAssignment() { + ], + }, + { + code: `function elementAccessWithoutAssignment() { const elementAccessWithoutAssignment: number[] = []; foo(elementAccessWithoutAssignment[1]); // Noncompliant }`, - errors: [ - { - messageId: 'reviewUsageOfIdentifier', - data: { - identifierName: 'elementAccessWithoutAssignment', + errors: [ + { + messageId: 'reviewUsageOfIdentifier', + data: { + identifierName: 'elementAccessWithoutAssignment', + }, }, - }, - ], - }, - { - code: `function okLatelyInitialized() { + ], + }, + { + code: `function okLatelyInitialized() { let arrayLatelyInitialized: number[]; arrayLatelyInitialized = []; arrayLatelyInitialized.forEach(item => console.log()); // Noncompliant }`, - errors: [ - { - messageId: 'reviewUsageOfIdentifier', - data: { - identifierName: 'arrayLatelyInitialized', + errors: [ + { + messageId: 'reviewUsageOfIdentifier', + data: { + identifierName: 'arrayLatelyInitialized', + }, }, - }, - ], - }, - { - code: `export let exportedArray: number[] = []; + ], + }, + { + code: `export let exportedArray: number[] = []; foo(exportedArray[1]); // Can be a FP, but it's a corner case`, - errors: [ - { - messageId: 'reviewUsageOfIdentifier', - data: { - identifierName: 'exportedArray', + errors: [ + { + messageId: 'reviewUsageOfIdentifier', + data: { + identifierName: 'exportedArray', + }, }, - }, - ], - }, - ], + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4165/unit.test.ts b/packages/jsts/src/rules/S4165/unit.test.ts index cf9e1ca30e..15f9f1f6ce 100644 --- a/packages/jsts/src/rules/S4165/unit.test.ts +++ b/packages/jsts/src/rules/S4165/unit.test.ts @@ -16,15 +16,16 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4165', () => { - const ruleTesterTs = new RuleTester(); + it('S4165', () => { + const ruleTesterTs = new RuleTester(); - ruleTesterTs.run('', rule, { - valid: [ - { - code: ` + ruleTesterTs.run('', rule, { + valid: [ + { + code: ` function circleOfAssignments (array) { var buffer = new Array(len); for (var chk = 1; chk < len; chk *= 2) { @@ -34,16 +35,16 @@ describe('S4165', () => { } } `, - }, - { - code: `function identities(x) { + }, + { + code: `function identities(x) { let y = x; let z = x; z = y; // FN }`, - }, - { - code: `function compliant(cond) { + }, + { + code: `function compliant(cond) { let x = 0; let mx = 0; if (cond) { @@ -51,9 +52,9 @@ describe('S4165', () => { mx = x; } }`, - }, - { - code: `function writtenInsideLoop(cond, items) { + }, + { + code: `function writtenInsideLoop(cond, items) { while (cond) { let x = 42; } @@ -61,9 +62,9 @@ describe('S4165', () => { const { id, state } = item } }`, - }, - { - code: `function sameConstraintsAcrossBranches(z) { + }, + { + code: `function sameConstraintsAcrossBranches(z) { let x; let y = z; if (check(x)) { // function using x in condition forces constraint to ANY_VALUE @@ -73,46 +74,46 @@ describe('S4165', () => { y = z; }`, - }, - { - code: `function differentStrictConstraints(x, y) { + }, + { + code: `function differentStrictConstraints(x, y) { if (x === "" && y === 0) { x = y; // OK } }`, - }, - { - code: `function unconstrainedSymbolicValues(x, y) { + }, + { + code: `function unconstrainedSymbolicValues(x, y) { x = y; // OK }`, - }, - { - code: `function unknownSymbolicValues() { + }, + { + code: `function unknownSymbolicValues() { u1 = u2; // OK }`, - }, - { - code: `function differentIdentities(x, y) { + }, + { + code: `function differentIdentities(x, y) { let z = y; z = x; // OK }`, - }, - { - code: `function nonSingleValueConstraints(x, y) { + }, + { + code: `function nonSingleValueConstraints(x, y) { if (x === "hello" && y === "hello") { x = y; // OK } }`, - }, - { - code: `function assignmentsWithOperation() { + }, + { + code: `function assignmentsWithOperation() { let x = 0; let y = x; y *= x; // OK }`, - }, - { - code: `function exceptions() { + }, + { + code: `function exceptions() { let x = ""; let y = { foo() { @@ -128,24 +129,24 @@ describe('S4165', () => { x = x // OK basic self-assignment already covered by S1656 }`, - }, - { - code: `function undef() { + }, + { + code: `function undef() { let x; let y; let z; z = x; // FN }`, - }, - { - code: `function singleValueConstraints(x, y) { + }, + { + code: `function singleValueConstraints(x, y) { if (x === "" && y === "") { x = y; // FN } }`, - }, - { - code: `function if_true_branch(pred1, pred2, param) { + }, + { + code: `function if_true_branch(pred1, pred2, param) { if (pred1) { param = 42; } @@ -153,9 +154,9 @@ describe('S4165', () => { param = 42; } }`, - }, - { - code: `function if_true_branch_no_param(pred1, pred2) { + }, + { + code: `function if_true_branch_no_param(pred1, pred2) { var localX; if (pred1) { localX = 42; @@ -164,30 +165,30 @@ describe('S4165', () => { localX = 42; } }`, - }, - { - code: `function var_increment(arr) { + }, + { + code: `function var_increment(arr) { for (var i = 0; i < arr.length; i++) { for (var j = 0; j < arr.length; j++) { console.log(arr[i] + arr[j]); } } }`, - }, - { - code: `const enum A { + }, + { + code: `const enum A { Monday = 1, Tuesday = 2 }`, - }, - { - code: `function using_destructuring() { + }, + { + code: `function using_destructuring() { let {a, ...rest} = {a: 42, b: 5}; a = 42; // FN }`, - }, - { - code: `function maybe_redundant() { + }, + { + code: `function maybe_redundant() { var n = 0; if (p) { n = 42; @@ -197,72 +198,72 @@ describe('S4165', () => { var x = 42; x = n; }`, - }, - { - code: `function function_call() { + }, + { + code: `function function_call() { var x = foo(); x = foo(); }`, - }, - { - code: `function increment() { + }, + { + code: `function increment() { let xxx = 42; let yyy = xxx; xxx++; yyy = xxx; }`, - }, - { - code: `function scanNumber(): string { + }, + { + code: `function scanNumber(): string { let end = pos; pos++; end = pos; }`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function overwrite() { let z = 42; z = 42; // Noncompliant {{Review this redundant assignment: "z" already holds the assigned value along all execution paths.}} }`, - errors: [ - { - message: - 'Review this redundant assignment: "z" already holds the assigned value along all execution paths.', - }, - ], - }, - { - code: `function nul() { + errors: [ + { + message: + 'Review this redundant assignment: "z" already holds the assigned value along all execution paths.', + }, + ], + }, + { + code: `function nul() { let x = null; let y = null; y = x; // Noncompliant //^^^^^ }`, - errors: 1, - }, - { - code: `function literalsNotYetDone() { + errors: 1, + }, + { + code: `function literalsNotYetDone() { let x = 1; let y = 1; let z = x; z = y; // Noncompliant }`, - errors: 1, - }, - { - code: `function rspecExample() { + errors: 1, + }, + { + code: `function rspecExample() { var b = 0; var a = b; var c = a; b = c; // Noncompliant }`, - errors: 1, - }, - { - code: `function if_then_else(p) { + errors: 1, + }, + { + code: `function if_then_else(p) { let xx = 0; if (p) { xx = 42; @@ -271,10 +272,10 @@ describe('S4165', () => { } xx = 42; }`, - errors: 1, - }, - { - code: `function outer() { + errors: 1, + }, + { + code: `function outer() { let x = 42; let y = 0; for (;;) { @@ -282,13 +283,14 @@ describe('S4165', () => { y = 42; } }`, - errors: [ - { - messageId: 'reviewAssignment', - line: 6, - }, - ], - }, - ], + errors: [ + { + messageId: 'reviewAssignment', + line: 6, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4275/unit.test.ts b/packages/jsts/src/rules/S4275/unit.test.ts index 2c39d27a9f..8ea3799681 100644 --- a/packages/jsts/src/rules/S4275/unit.test.ts +++ b/packages/jsts/src/rules/S4275/unit.test.ts @@ -16,33 +16,34 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4275', () => { - const ruleTester = new RuleTester(); - - function missingReturn(...codes: string[]) { - return codes.map(code => ({ - code, - errors: ['{"message":"Refactor this getter to return a value.","secondaryLocations":[]}'], - options: [{}, 'sonar-runtime'], - })); - } - - function missingAlwaysReturn(...codes: string[]) { - return codes.map(code => ({ - code, - errors: [ - '{"message":"Refactor this getter to always return a value.","secondaryLocations":[]}', - ], - options: [{}, 'sonar-runtime'], - })); - } - - ruleTester.run('Getters and setters should access the expected fields', rule, { - valid: [ - { - code: ` + it('S4275', () => { + const ruleTester = new RuleTester(); + + function missingReturn(...codes: string[]) { + return codes.map(code => ({ + code, + errors: ['{"message":"Refactor this getter to return a value.","secondaryLocations":[]}'], + options: [{}, 'sonar-runtime'], + })); + } + + function missingAlwaysReturn(...codes: string[]) { + return codes.map(code => ({ + code, + errors: [ + '{"message":"Refactor this getter to always return a value.","secondaryLocations":[]}', + ], + options: [{}, 'sonar-runtime'], + })); + } + + ruleTester.run('Getters and setters should access the expected fields', rule, { + valid: [ + { + code: ` class OK { private x: string; private _y = "hello"; @@ -75,9 +76,9 @@ describe('S4275', () => { this.x = x; } }`, - }, - { - code: ` + }, + { + code: ` class Exceptions1 { private x: string; private y = "hello"; @@ -133,9 +134,9 @@ describe('S4275', () => { return \`v is \${this.z}\`; } }`, - }, - { - code: ` + }, + { + code: ` class Exceptions2 { private x: string; private y = "hello"; @@ -153,9 +154,9 @@ describe('S4275', () => { return this.x; } }`, - }, - { - code: ` + }, + { + code: ` export const ObjectLiteral = { w_: "blah", _x: "blah", @@ -196,30 +197,30 @@ describe('S4275', () => { ...theRest };`, - }, - { code: 'Object.defineProperty()' }, - { code: 'Object.defineProperty(o)' }, - { code: 'Object.defineProperty(o, "b")' }, - { code: 'Object.defineProperty(o, "b", props)' }, - { code: 'Object.defineProperty(o, "b", { get() { return a; } })' }, - { code: 'let _b = 0, _c = 0; Object.defineProperty(o, "b", { get() { return _b; } })' }, - { code: 'Reflect.defineProperty()' }, - { code: 'Reflect.defineProperty(o)' }, - { code: 'Reflect.defineProperty(o, "b")' }, - { code: 'Reflect.defineProperty(o, "b", props)' }, - { code: 'Reflect.defineProperty(o, "b", { get() { return a; } })' }, - { code: 'Object.defineProperties()' }, - { code: 'Object.defineProperties(o)' }, - { code: 'Object.defineProperties(o, props)' }, - { code: 'Object.defineProperties(o, { b: { get() { return a; } } })' }, - { code: 'Object.create()' }, - { code: 'Object.create(o)' }, - { code: 'Object.create(o, props)' }, - { code: 'Object.create(o, { b: { get() { return a; } } })' }, - ], - invalid: [ - { - code: ` + }, + { code: 'Object.defineProperty()' }, + { code: 'Object.defineProperty(o)' }, + { code: 'Object.defineProperty(o, "b")' }, + { code: 'Object.defineProperty(o, "b", props)' }, + { code: 'Object.defineProperty(o, "b", { get() { return a; } })' }, + { code: 'let _b = 0, _c = 0; Object.defineProperty(o, "b", { get() { return _b; } })' }, + { code: 'Reflect.defineProperty()' }, + { code: 'Reflect.defineProperty(o)' }, + { code: 'Reflect.defineProperty(o, "b")' }, + { code: 'Reflect.defineProperty(o, "b", props)' }, + { code: 'Reflect.defineProperty(o, "b", { get() { return a; } })' }, + { code: 'Object.defineProperties()' }, + { code: 'Object.defineProperties(o)' }, + { code: 'Object.defineProperties(o, props)' }, + { code: 'Object.defineProperties(o, { b: { get() { return a; } } })' }, + { code: 'Object.create()' }, + { code: 'Object.create(o)' }, + { code: 'Object.create(o, props)' }, + { code: 'Object.create(o, { b: { get() { return a; } } })' }, + ], + invalid: [ + { + code: ` class A { _x: number = 0; _y: number = 0; @@ -229,17 +230,17 @@ describe('S4275', () => { } } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` let a = 0; Object.defineProperty(obj, 'a', { get() {} }); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` class NOK_CheckLocation { private x: string; private _y = "hello"; @@ -250,48 +251,48 @@ describe('S4275', () => { return this._y; } }`, - errors: [ - { - message: JSON.stringify({ - message: "Refactor this setter so that it actually refers to the property '_y'.", - secondaryLocations: [ - { - message: 'Property which should be referred.', - column: 8, - line: 4, - endColumn: 29, - endLine: 4, - }, - ], - }), - line: 6, - column: 16, - endLine: 6, - endColumn: 20, - }, - { - message: JSON.stringify({ - message: "Refactor this getter so that it actually refers to the property 'x'.", - secondaryLocations: [ - { - message: 'Property which should be referred.', - column: 8, - line: 3, - endColumn: 26, - endLine: 3, - }, - ], - }), - line: 8, - column: 20, - endLine: 8, - endColumn: 21, - }, - ], - options: [{}, 'sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: "Refactor this setter so that it actually refers to the property '_y'.", + secondaryLocations: [ + { + message: 'Property which should be referred.', + column: 8, + line: 4, + endColumn: 29, + endLine: 4, + }, + ], + }), + line: 6, + column: 16, + endLine: 6, + endColumn: 20, + }, + { + message: JSON.stringify({ + message: "Refactor this getter so that it actually refers to the property 'x'.", + secondaryLocations: [ + { + message: 'Property which should be referred.', + column: 8, + line: 3, + endColumn: 26, + endLine: 3, + }, + ], + }), + line: 8, + column: 20, + endLine: 8, + endColumn: 21, + }, + ], + options: [{}, 'sonar-runtime'], + }, + { + code: ` class NOK { static _filter: string = ''; private _filter: string = ''; @@ -312,206 +313,206 @@ describe('S4275', () => { public get y(): number { return this._x; } // Noncompliant }`, - errors: [ - { - message: JSON.stringify({ - message: "Refactor this getter so that it actually refers to the property '_y'.", - secondaryLocations: [ - { - message: 'Property which should be referred.', - column: 8, - line: 9, - endColumn: 31, - endLine: 9, - }, - ], - }), - line: 20, - column: 20, - endLine: 20, - endColumn: 21, - }, - ], - options: [{}, 'sonar-runtime'], - }, - { - code: `const foo = { + errors: [ + { + message: JSON.stringify({ + message: "Refactor this getter so that it actually refers to the property '_y'.", + secondaryLocations: [ + { + message: 'Property which should be referred.', + column: 8, + line: 9, + endColumn: 31, + endLine: 9, + }, + ], + }), + line: 20, + column: 20, + endLine: 20, + endColumn: 21, + }, + ], + options: [{}, 'sonar-runtime'], + }, + { + code: `const foo = { _bar: 0, get bar() { } };`, - errors: [ - { - message: JSON.stringify({ - message: "Refactor this getter so that it actually refers to the property '_bar'.", - secondaryLocations: [ - { - message: 'Property which should be referred.', - column: 8, - line: 2, - endColumn: 15, - endLine: 2, - }, - ], - }), - line: 3, - column: 13, - endLine: 3, - endColumn: 16, - }, - ], - options: [{}, 'sonar-runtime'], - }, - { - code: `class foo { + errors: [ + { + message: JSON.stringify({ + message: "Refactor this getter so that it actually refers to the property '_bar'.", + secondaryLocations: [ + { + message: 'Property which should be referred.', + column: 8, + line: 2, + endColumn: 15, + endLine: 2, + }, + ], + }), + line: 3, + column: 13, + endLine: 3, + endColumn: 16, + }, + ], + options: [{}, 'sonar-runtime'], + }, + { + code: `class foo { _bar = 0; get bar() { } }`, - errors: [ - { - message: JSON.stringify({ - message: "Refactor this getter so that it actually refers to the property '_bar'.", - secondaryLocations: [ - { - message: 'Property which should be referred.', - column: 8, - line: 2, - endColumn: 17, - endLine: 2, - }, - ], - }), - line: 3, - column: 13, - endLine: 3, - endColumn: 16, - }, - ], - options: [{}, 'sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: "Refactor this getter so that it actually refers to the property '_bar'.", + secondaryLocations: [ + { + message: 'Property which should be referred.', + column: 8, + line: 2, + endColumn: 17, + endLine: 2, + }, + ], + }), + line: 3, + column: 13, + endLine: 3, + endColumn: 16, + }, + ], + options: [{}, 'sonar-runtime'], + }, + { + code: ` let bar = 0; Object.defineProperty(obj, 'bar', { get() {} }); `, - errors: [ - { - message: JSON.stringify({ - message: "Refactor this getter so that it actually refers to the variable 'bar'.", - secondaryLocations: [ - { - message: 'Variable which should be referred.', - column: 10, - line: 2, - endColumn: 17, - endLine: 2, - }, - ], - }), - line: 3, - column: 43, - endLine: 3, - endColumn: 46, - }, - ], - options: [{}, 'sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: "Refactor this getter so that it actually refers to the variable 'bar'.", + secondaryLocations: [ + { + message: 'Variable which should be referred.', + column: 10, + line: 2, + endColumn: 17, + endLine: 2, + }, + ], + }), + line: 3, + column: 43, + endLine: 3, + endColumn: 46, + }, + ], + options: [{}, 'sonar-runtime'], + }, + { + code: ` function foo(bar) { Object.defineProperties(obj, { bar: { get() {} } }); } `, - errors: [ - { - message: JSON.stringify({ - message: "Refactor this getter so that it actually refers to the variable 'bar'.", - secondaryLocations: [ - { - message: 'Variable which should be referred.', - column: 6, - line: 2, - endColumn: 7, - endLine: 4, - }, - ], - }), - line: 3, - column: 47, - endLine: 3, - endColumn: 50, - }, - ], - options: [{}, 'sonar-runtime'], - }, - { - code: `class foo { + errors: [ + { + message: JSON.stringify({ + message: "Refactor this getter so that it actually refers to the variable 'bar'.", + secondaryLocations: [ + { + message: 'Variable which should be referred.', + column: 6, + line: 2, + endColumn: 7, + endLine: 4, + }, + ], + }), + line: 3, + column: 47, + endLine: 3, + endColumn: 50, + }, + ], + options: [{}, 'sonar-runtime'], + }, + { + code: `class foo { #bar = 0; get bar() { } }`, - errors: [ - { - message: JSON.stringify({ - message: "Refactor this getter so that it actually refers to the property 'bar'.", - secondaryLocations: [ - { - message: 'Property which should be referred.', - column: 8, - line: 2, - endColumn: 17, - endLine: 2, - }, - ], - }), - line: 3, - column: 13, - endLine: 3, - endColumn: 16, - }, - ], - options: [{}, 'sonar-runtime'], - }, - { - code: `const foo = { + errors: [ + { + message: JSON.stringify({ + message: "Refactor this getter so that it actually refers to the property 'bar'.", + secondaryLocations: [ + { + message: 'Property which should be referred.', + column: 8, + line: 2, + endColumn: 17, + endLine: 2, + }, + ], + }), + line: 3, + column: 13, + endLine: 3, + endColumn: 16, + }, + ], + options: [{}, 'sonar-runtime'], + }, + { + code: `const foo = { get bar() { } };`, - errors: [ - { - message: JSON.stringify({ - message: 'Refactor this getter to return a value.', - secondaryLocations: [], - }), - line: 2, - column: 9, - endLine: 2, - endColumn: 16, - }, - ], - options: [{}, 'sonar-runtime'], - }, - { - code: `class Foo { + errors: [ + { + message: JSON.stringify({ + message: 'Refactor this getter to return a value.', + secondaryLocations: [], + }), + line: 2, + column: 9, + endLine: 2, + endColumn: 16, + }, + ], + options: [{}, 'sonar-runtime'], + }, + { + code: `class Foo { get bar(): string {} }`, - errors: [ - { - message: JSON.stringify({ - message: 'Refactor this getter to return a value.', - secondaryLocations: [], - }), - line: 2, - column: 9, - endLine: 2, - endColumn: 16, - }, - ], - options: [{}, 'sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: 'Refactor this getter to return a value.', + secondaryLocations: [], + }), + line: 2, + column: 9, + endLine: 2, + endColumn: 16, + }, + ], + options: [{}, 'sonar-runtime'], + }, + { + code: ` let b = 42; let c = 38; Object.defineProperty(o, "b", { @@ -525,48 +526,48 @@ describe('S4275', () => { configurable: true, }); `, - errors: [ - { - message: JSON.stringify({ - message: "Refactor this getter so that it actually refers to the variable 'b'.", - secondaryLocations: [ - { - message: 'Variable which should be referred.', - column: 12, - line: 2, - endColumn: 18, - endLine: 2, - }, - ], - }), - line: 5, - column: 11, - endLine: 5, - endColumn: 14, - }, - { - message: JSON.stringify({ - message: "Refactor this setter so that it actually refers to the variable 'b'.", - secondaryLocations: [ - { - message: 'Variable which should be referred.', - column: 12, - line: 2, - endColumn: 18, - endLine: 2, - }, - ], - }), - line: 8, - column: 11, - endLine: 8, - endColumn: 14, - }, - ], - options: [{}, 'sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: "Refactor this getter so that it actually refers to the variable 'b'.", + secondaryLocations: [ + { + message: 'Variable which should be referred.', + column: 12, + line: 2, + endColumn: 18, + endLine: 2, + }, + ], + }), + line: 5, + column: 11, + endLine: 5, + endColumn: 14, + }, + { + message: JSON.stringify({ + message: "Refactor this setter so that it actually refers to the variable 'b'.", + secondaryLocations: [ + { + message: 'Variable which should be referred.', + column: 12, + line: 2, + endColumn: 18, + endLine: 2, + }, + ], + }), + line: 8, + column: 11, + endLine: 8, + endColumn: 14, + }, + ], + options: [{}, 'sonar-runtime'], + }, + { + code: ` let b = 42; let c = 38; Reflect.defineProperty(o, "b", { @@ -580,10 +581,10 @@ describe('S4275', () => { configurable: true, }); `, - errors: 2, - }, - { - code: ` + errors: 2, + }, + { + code: ` let b = 42; let c = 38; Reflect.defineProperty(o, "b", { @@ -596,30 +597,30 @@ describe('S4275', () => { configurable: true, }); `, - errors: [ - { - message: JSON.stringify({ - message: "Refactor this setter so that it actually refers to the variable 'b'.", - secondaryLocations: [ - { - message: 'Variable which should be referred.', - column: 12, - line: 2, - endColumn: 18, - endLine: 2, - }, - ], - }), - line: 8, - column: 11, - endLine: 8, - endColumn: 14, - }, - ], - options: [{}, 'sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: "Refactor this setter so that it actually refers to the variable 'b'.", + secondaryLocations: [ + { + message: 'Variable which should be referred.', + column: 12, + line: 2, + endColumn: 18, + endLine: 2, + }, + ], + }), + line: 8, + column: 11, + endLine: 8, + endColumn: 14, + }, + ], + options: [{}, 'sonar-runtime'], + }, + { + code: ` let b = 42; let c = 38; let d = 46; @@ -656,102 +657,102 @@ describe('S4275', () => { } ); `, - errors: [ - { - message: JSON.stringify({ - message: "Refactor this getter so that it actually refers to the variable 'b'.", - secondaryLocations: [ - { - message: 'Variable which should be referred.', - column: 12, - line: 2, - endColumn: 18, - endLine: 2, - }, - ], - }), - line: 7, - column: 13, - endLine: 7, - endColumn: 16, - }, - { - message: JSON.stringify({ - message: "Refactor this setter so that it actually refers to the variable 'b'.", - secondaryLocations: [ - { - message: 'Variable which should be referred.', - column: 12, - line: 2, - endColumn: 18, - endLine: 2, - }, - ], - }), - line: 10, - column: 13, - endLine: 10, - endColumn: 16, - }, - { - message: JSON.stringify({ - message: "Refactor this setter so that it actually refers to the variable 'c'.", - secondaryLocations: [ - { - message: 'Variable which should be referred.', - column: 12, - line: 3, - endColumn: 18, - endLine: 3, - }, - ], - }), - line: 20, - column: 13, - endLine: 20, - endColumn: 16, - }, - { - message: JSON.stringify({ - message: "Refactor this getter so that it actually refers to the variable 'd'.", - secondaryLocations: [ - { - message: 'Variable which should be referred.', - column: 12, - line: 4, - endColumn: 18, - endLine: 4, - }, - ], - }), - line: 26, - column: 13, - endLine: 26, - endColumn: 16, - }, - { - message: JSON.stringify({ - message: "Refactor this setter so that it actually refers to the variable 'd'.", - secondaryLocations: [ - { - message: 'Variable which should be referred.', - column: 12, - line: 4, - endColumn: 18, - endLine: 4, - }, - ], - }), - line: 29, - column: 13, - endLine: 29, - endColumn: 16, - }, - ], - options: [{}, 'sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: "Refactor this getter so that it actually refers to the variable 'b'.", + secondaryLocations: [ + { + message: 'Variable which should be referred.', + column: 12, + line: 2, + endColumn: 18, + endLine: 2, + }, + ], + }), + line: 7, + column: 13, + endLine: 7, + endColumn: 16, + }, + { + message: JSON.stringify({ + message: "Refactor this setter so that it actually refers to the variable 'b'.", + secondaryLocations: [ + { + message: 'Variable which should be referred.', + column: 12, + line: 2, + endColumn: 18, + endLine: 2, + }, + ], + }), + line: 10, + column: 13, + endLine: 10, + endColumn: 16, + }, + { + message: JSON.stringify({ + message: "Refactor this setter so that it actually refers to the variable 'c'.", + secondaryLocations: [ + { + message: 'Variable which should be referred.', + column: 12, + line: 3, + endColumn: 18, + endLine: 3, + }, + ], + }), + line: 20, + column: 13, + endLine: 20, + endColumn: 16, + }, + { + message: JSON.stringify({ + message: "Refactor this getter so that it actually refers to the variable 'd'.", + secondaryLocations: [ + { + message: 'Variable which should be referred.', + column: 12, + line: 4, + endColumn: 18, + endLine: 4, + }, + ], + }), + line: 26, + column: 13, + endLine: 26, + endColumn: 16, + }, + { + message: JSON.stringify({ + message: "Refactor this setter so that it actually refers to the variable 'd'.", + secondaryLocations: [ + { + message: 'Variable which should be referred.', + column: 12, + line: 4, + endColumn: 18, + endLine: 4, + }, + ], + }), + line: 29, + column: 13, + endLine: 29, + endColumn: 16, + }, + ], + options: [{}, 'sonar-runtime'], + }, + { + code: ` let b = 42; let c = 38; let d = 46; @@ -788,28 +789,28 @@ describe('S4275', () => { } ); `, - errors: 5, - }, - ...missingReturn( - 'var foo = { get bar() { return; } };', - 'class foo { get bar(){} }', - 'var foo = class {\n static get\nbar(){} }', - "Object.defineProperty(foo, 'bar', { get: function(){}});", - "Object.defineProperty(foo, 'bar', { get: function getfoo (){}});", - "Object.defineProperty(foo, 'bar', { get(){} });", - "Object.defineProperty(foo, 'bar', { get: () => {}});", - "Reflect.defineProperty(foo, 'bar', { get: function (){}});", - 'Object.create(foo, { bar: { get: function() {} } })', - 'Object.create(foo, { bar: { get() {} } })', - 'Object.create(foo, { bar: { get: () => {} } })', - ), - ...missingAlwaysReturn( - 'var foo = { get bar(){if(baz) {return true;}} };', - 'class foo { get bar(){ if (baz) { return true; }}}', - 'Object.defineProperty(foo, "bar", { get: function (){if(bar) {return true;}}});', - ), - { - code: ` + errors: 5, + }, + ...missingReturn( + 'var foo = { get bar() { return; } };', + 'class foo { get bar(){} }', + 'var foo = class {\n static get\nbar(){} }', + "Object.defineProperty(foo, 'bar', { get: function(){}});", + "Object.defineProperty(foo, 'bar', { get: function getfoo (){}});", + "Object.defineProperty(foo, 'bar', { get(){} });", + "Object.defineProperty(foo, 'bar', { get: () => {}});", + "Reflect.defineProperty(foo, 'bar', { get: function (){}});", + 'Object.create(foo, { bar: { get: function() {} } })', + 'Object.create(foo, { bar: { get() {} } })', + 'Object.create(foo, { bar: { get: () => {} } })', + ), + ...missingAlwaysReturn( + 'var foo = { get bar(){if(baz) {return true;}} };', + 'class foo { get bar(){ if (baz) { return true; }}}', + 'Object.defineProperty(foo, "bar", { get: function (){if(bar) {return true;}}});', + ), + { + code: ` class NOK { private x: string; private _y = "hello"; @@ -847,44 +848,44 @@ describe('S4275', () => { this.z = ro; } }`, - errors: [ - { - message: - '{"message":"Refactor this setter so that it actually refers to the property \'x\'.","secondaryLocations":[{"message":"Property which should be referred.","column":6,"line":3,"endColumn":24,"endLine":3}]}', - }, - { - message: - '{"message":"Refactor this getter so that it actually refers to the property \'x\'.","secondaryLocations":[{"message":"Property which should be referred.","column":6,"line":3,"endColumn":24,"endLine":3}]}', - }, - { - message: - '{"message":"Refactor this getter so that it actually refers to the property \'_y\'.","secondaryLocations":[{"message":"Property which should be referred.","column":6,"line":4,"endColumn":27,"endLine":4}]}', - }, - { - message: - '{"message":"Refactor this setter so that it actually refers to the property \'_y\'.","secondaryLocations":[{"message":"Property which should be referred.","column":6,"line":4,"endColumn":27,"endLine":4}]}', - }, - { - message: - '{"message":"Refactor this getter so that it actually refers to the property \'_y\'.","secondaryLocations":[{"message":"Property which should be referred.","column":6,"line":4,"endColumn":27,"endLine":4}]}', - }, - { - message: - '{"message":"Refactor this setter so that it actually refers to the property \'z\'.","secondaryLocations":[{"message":"Property which should be referred.","column":6,"line":5,"endColumn":20,"endLine":5}]}', - }, - { - message: - '{"message":"Refactor this setter so that it actually refers to the property \'w\'.","secondaryLocations":[{"message":"Property which should be referred.","column":18,"line":7,"endColumn":35,"endLine":7}]}', - }, - { - message: - '{"message":"Refactor this setter so that it actually refers to the property \'ro\'.","secondaryLocations":[{"message":"Property which should be referred.","column":37,"line":7,"endColumn":56,"endLine":7}]}', - }, - ], - options: [{}, 'sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: + '{"message":"Refactor this setter so that it actually refers to the property \'x\'.","secondaryLocations":[{"message":"Property which should be referred.","column":6,"line":3,"endColumn":24,"endLine":3}]}', + }, + { + message: + '{"message":"Refactor this getter so that it actually refers to the property \'x\'.","secondaryLocations":[{"message":"Property which should be referred.","column":6,"line":3,"endColumn":24,"endLine":3}]}', + }, + { + message: + '{"message":"Refactor this getter so that it actually refers to the property \'_y\'.","secondaryLocations":[{"message":"Property which should be referred.","column":6,"line":4,"endColumn":27,"endLine":4}]}', + }, + { + message: + '{"message":"Refactor this setter so that it actually refers to the property \'_y\'.","secondaryLocations":[{"message":"Property which should be referred.","column":6,"line":4,"endColumn":27,"endLine":4}]}', + }, + { + message: + '{"message":"Refactor this getter so that it actually refers to the property \'_y\'.","secondaryLocations":[{"message":"Property which should be referred.","column":6,"line":4,"endColumn":27,"endLine":4}]}', + }, + { + message: + '{"message":"Refactor this setter so that it actually refers to the property \'z\'.","secondaryLocations":[{"message":"Property which should be referred.","column":6,"line":5,"endColumn":20,"endLine":5}]}', + }, + { + message: + '{"message":"Refactor this setter so that it actually refers to the property \'w\'.","secondaryLocations":[{"message":"Property which should be referred.","column":18,"line":7,"endColumn":35,"endLine":7}]}', + }, + { + message: + '{"message":"Refactor this setter so that it actually refers to the property \'ro\'.","secondaryLocations":[{"message":"Property which should be referred.","column":37,"line":7,"endColumn":56,"endLine":7}]}', + }, + ], + options: [{}, 'sonar-runtime'], + }, + { + code: ` const nokObj = { w_: 0, x : 3, @@ -916,34 +917,35 @@ describe('S4275', () => { return this.x; }, }`, - errors: [ - { - message: - '{"message":"Refactor this getter so that it actually refers to the property \'w_\'.","secondaryLocations":[{"message":"Property which should be referred.","column":6,"line":3,"endColumn":11,"endLine":3}]}', - }, - { - message: - '{"message":"Refactor this getter so that it actually refers to the property \'_y\'.","secondaryLocations":[{"message":"Property which should be referred.","column":6,"line":5,"endColumn":12,"endLine":5}]}', - }, - { - message: - '{"message":"Refactor this setter so that it actually refers to the property \'x\'.","secondaryLocations":[{"message":"Property which should be referred.","column":6,"line":4,"endColumn":11,"endLine":4}]}', - }, - { - message: - '{"message":"Refactor this getter so that it actually refers to the property \'z\'.","secondaryLocations":[{"message":"Property which should be referred.","column":6,"line":6,"endColumn":12,"endLine":6}]}', - }, - { - message: - '{"message":"Refactor this setter so that it actually refers to the property \'z\'.","secondaryLocations":[{"message":"Property which should be referred.","column":6,"line":6,"endColumn":12,"endLine":6}]}', - }, - ], - options: [{}, 'sonar-runtime'], - }, - { - code: 'let _b = 0, _c = 0; Object.defineProperty(o, "b", { get() { return _c; } })', - errors: 1, - }, - ], + errors: [ + { + message: + '{"message":"Refactor this getter so that it actually refers to the property \'w_\'.","secondaryLocations":[{"message":"Property which should be referred.","column":6,"line":3,"endColumn":11,"endLine":3}]}', + }, + { + message: + '{"message":"Refactor this getter so that it actually refers to the property \'_y\'.","secondaryLocations":[{"message":"Property which should be referred.","column":6,"line":5,"endColumn":12,"endLine":5}]}', + }, + { + message: + '{"message":"Refactor this setter so that it actually refers to the property \'x\'.","secondaryLocations":[{"message":"Property which should be referred.","column":6,"line":4,"endColumn":11,"endLine":4}]}', + }, + { + message: + '{"message":"Refactor this getter so that it actually refers to the property \'z\'.","secondaryLocations":[{"message":"Property which should be referred.","column":6,"line":6,"endColumn":12,"endLine":6}]}', + }, + { + message: + '{"message":"Refactor this setter so that it actually refers to the property \'z\'.","secondaryLocations":[{"message":"Property which should be referred.","column":6,"line":6,"endColumn":12,"endLine":6}]}', + }, + ], + options: [{}, 'sonar-runtime'], + }, + { + code: 'let _b = 0, _c = 0; Object.defineProperty(o, "b", { get() { return _c; } })', + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4322/unit.test.ts b/packages/jsts/src/rules/S4322/unit.test.ts index 280252e178..36c38ba233 100644 --- a/packages/jsts/src/rules/S4322/unit.test.ts +++ b/packages/jsts/src/rules/S4322/unit.test.ts @@ -16,88 +16,89 @@ */ import { rule } from './index.js'; import { NoTypeCheckingRuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4322', () => { - const ruleTester = new NoTypeCheckingRuleTester(); + it('S4322', () => { + const ruleTester = new NoTypeCheckingRuleTester(); - ruleTester.run('Type guards should be used', rule, { - valid: [ - { - code: `function isFish(animal: Animal): animal is Fish { + ruleTester.run('Type guards should be used', rule, { + valid: [ + { + code: `function isFish(animal: Animal): animal is Fish { return (animal as Fish).swim !== undefined; }`, - }, - { - code: `function isFish(animal: Animal) { + }, + { + code: `function isFish(animal: Animal) { return (animal as Fish).swim !== null; }`, - }, - { - code: `function isFish(animal: Animal) { + }, + { + code: `function isFish(animal: Animal) { console.log((animal as Fish).swim !== null); }`, - }, - { - code: `// "any" type is excluded + }, + { + code: `// "any" type is excluded function isFish(animal: Animal) { return (animal as any).swim != undefined; }`, - }, - { - code: `function isNotFish(animal: Animal) { + }, + { + code: `function isNotFish(animal: Animal) { return !((animal as Fish).swim); }`, - }, - { - code: `// OK, not a member expression + }, + { + code: `// OK, not a member expression function isFish(animal: Animal) { return !!(animal as Fish); }`, - }, - { - code: `// OK, more than one statement + }, + { + code: `// OK, more than one statement function isFish(animal: Animal) { console.log("FOO"); return !!((animal as Fish).swim); }`, - }, - { - code: `// OK, more than one argument + }, + { + code: `// OK, more than one argument function isFish(animal: Animal, foo: String) { return !!((animal as Fish).swim); }`, - }, - { - code: `// OK, no type casting + }, + { + code: `// OK, no type casting function isFish(animal: Animal) { return !!animal.name; }`, - }, - { - filename: 'file.ts', // Default of rule tester is .tsx, and jsx enabled crashes the parsing of TS casting - code: `// Arrow functions are ignored + }, + { + filename: 'file.ts', // Default of rule tester is .tsx, and jsx enabled crashes the parsing of TS casting + code: `// Arrow functions are ignored let typePredicate = (animal: Animal) => !!(animal as Fish).swim; let typePredicateOK = (animal: Animal): animal is Fish => !!(animal as Fish).swim; let animals : Animal[] = []; let fishes = animals.filter((animal: Animal) => !!(animal as Fish).swim); let fishes = animals.filter((animal: Animal) => !!(animal).swim); let fishesOK = animals.filter((animal: Animal): animal is Fish => !!(animal as Fish).swim);`, - }, - { - code: `// Function Expressions are ignored + }, + { + code: `// Function Expressions are ignored let isFish = function (animal: Animal) { return (animal as Fish).swim !== undefined; } let isFishOK = function (animal: Animal) : animal is Fish { return (animal as Fish).swim !== undefined; }`, - }, - { - code: `declare function isFishNoBody(): boolean`, - }, - { - code: `// Disjoint union types + }, + { + code: `declare function isFishNoBody(): boolean`, + }, + { + code: `// Disjoint union types type A1 = { common: 1, a1: string @@ -117,165 +118,165 @@ describe('S4322', () => { function isSomeA1(param: A1 | A2) { return param.common === 1 && param.a1 === "Hello"; }`, - }, - ], - invalid: [ - { - code: `function isFish(animal: Animal) { + }, + ], + invalid: [ + { + code: `function isFish(animal: Animal) { return (animal as Fish).swim !== undefined; }`, - errors: [ - { - message: `Declare this function return type using type predicate "animal is Fish".`, - line: 1, - column: 10, - endLine: 1, - endColumn: 16, - suggestions: [ - { - desc: 'Use type predicate', - output: `function isFish(animal: Animal): animal is Fish { + errors: [ + { + message: `Declare this function return type using type predicate "animal is Fish".`, + line: 1, + column: 10, + endLine: 1, + endColumn: 16, + suggestions: [ + { + desc: 'Use type predicate', + output: `function isFish(animal: Animal): animal is Fish { return (animal as Fish).swim !== undefined; }`, - }, - ], - }, - ], - }, - { - code: `// With explicit return type + }, + ], + }, + ], + }, + { + code: `// With explicit return type function isFish(animal: Animal) : boolean { // Noncompliant return (animal as Fish).swim !== undefined; }`, - errors: [ - { - message: `Declare this function return type using type predicate "animal is Fish".`, - suggestions: [ - { - desc: 'Use type predicate', - output: `// With explicit return type + errors: [ + { + message: `Declare this function return type using type predicate "animal is Fish".`, + suggestions: [ + { + desc: 'Use type predicate', + output: `// With explicit return type function isFish(animal: Animal) : animal is Fish { // Noncompliant return (animal as Fish).swim !== undefined; }`, - }, - ], - }, - ], - }, - { - code: `function isFish(animal: Animal) { // Noncompliant + }, + ], + }, + ], + }, + { + code: `function isFish(animal: Animal) { // Noncompliant return undefined !== (animal as Fish).swim; }`, - errors: [ - { - message: `Declare this function return type using type predicate "animal is Fish".`, - suggestions: [ - { - desc: 'Use type predicate', - output: `function isFish(animal: Animal): animal is Fish { // Noncompliant + errors: [ + { + message: `Declare this function return type using type predicate "animal is Fish".`, + suggestions: [ + { + desc: 'Use type predicate', + output: `function isFish(animal: Animal): animal is Fish { // Noncompliant return undefined !== (animal as Fish).swim; }`, - }, - ], - }, - ], - }, - { - code: `// With loose inequality + }, + ], + }, + ], + }, + { + code: `// With loose inequality function isFish(animal: Animal) { // Noncompliant return (animal as Fish).swim != undefined; }`, - errors: [ - { - message: `Declare this function return type using type predicate "animal is Fish".`, - suggestions: [ - { - desc: 'Use type predicate', - output: `// With loose inequality + errors: [ + { + message: `Declare this function return type using type predicate "animal is Fish".`, + suggestions: [ + { + desc: 'Use type predicate', + output: `// With loose inequality function isFish(animal: Animal): animal is Fish { // Noncompliant return (animal as Fish).swim != undefined; }`, - }, - ], - }, - ], - }, - { - filename: 'file.ts', - code: `function isFish(animal: Animal) { // Noncompliant + }, + ], + }, + ], + }, + { + filename: 'file.ts', + code: `function isFish(animal: Animal) { // Noncompliant return ( animal).swim !== undefined; }`, - errors: [ - { - message: `Declare this function return type using type predicate "animal is Fish".`, - suggestions: [ - { - desc: 'Use type predicate', - output: `function isFish(animal: Animal): animal is Fish { // Noncompliant + errors: [ + { + message: `Declare this function return type using type predicate "animal is Fish".`, + suggestions: [ + { + desc: 'Use type predicate', + output: `function isFish(animal: Animal): animal is Fish { // Noncompliant return ( animal).swim !== undefined; }`, - }, - ], - }, - ], - }, - { - code: `function isFish(animal: Animal) { // Noncompliant + }, + ], + }, + ], + }, + { + code: `function isFish(animal: Animal) { // Noncompliant return Boolean((animal as Fish).swim); }`, - errors: [ - { - message: `Declare this function return type using type predicate "animal is Fish".`, - suggestions: [ - { - desc: 'Use type predicate', - output: `function isFish(animal: Animal): animal is Fish { // Noncompliant + errors: [ + { + message: `Declare this function return type using type predicate "animal is Fish".`, + suggestions: [ + { + desc: 'Use type predicate', + output: `function isFish(animal: Animal): animal is Fish { // Noncompliant return Boolean((animal as Fish).swim); }`, - }, - ], - }, - ], - }, - { - code: `function isFish(animal: Animal) { // Noncompliant + }, + ], + }, + ], + }, + { + code: `function isFish(animal: Animal) { // Noncompliant return !!((animal as Fish).swim); }`, - errors: [ - { - message: `Declare this function return type using type predicate "animal is Fish".`, - suggestions: [ - { - desc: 'Use type predicate', - output: `function isFish(animal: Animal): animal is Fish { // Noncompliant + errors: [ + { + message: `Declare this function return type using type predicate "animal is Fish".`, + suggestions: [ + { + desc: 'Use type predicate', + output: `function isFish(animal: Animal): animal is Fish { // Noncompliant return !!((animal as Fish).swim); }`, - }, - ], - }, - ], - }, - { - filename: 'file.ts', - code: `function isFish(animal: Animal) { // Noncompliant + }, + ], + }, + ], + }, + { + filename: 'file.ts', + code: `function isFish(animal: Animal) { // Noncompliant return (animal).swim !== undefined; }`, - errors: [ - { - message: `Declare this function return type using type predicate "animal is Fish".`, - suggestions: [ - { - desc: 'Use type predicate', - output: `function isFish(animal: Animal): animal is Fish { // Noncompliant + errors: [ + { + message: `Declare this function return type using type predicate "animal is Fish".`, + suggestions: [ + { + desc: 'Use type predicate', + output: `function isFish(animal: Animal): animal is Fish { // Noncompliant return (animal).swim !== undefined; }`, - }, - ], - }, - ], - }, - { - code: `// Type predicate on "this" + }, + ], + }, + ], + }, + { + code: `// Type predicate on "this" class Animal { swim?: Function; isFish(): boolean { // Noncompliant @@ -286,17 +287,17 @@ describe('S4322', () => { return !!(this as Fish).swim; } }`, - errors: [ - { - message: `Declare this function return type using type predicate "this is Fish".`, - line: 4, - column: 13, - endLine: 4, - endColumn: 19, - suggestions: [ - { - desc: 'Use type predicate', - output: `// Type predicate on "this" + errors: [ + { + message: `Declare this function return type using type predicate "this is Fish".`, + line: 4, + column: 13, + endLine: 4, + endColumn: 19, + suggestions: [ + { + desc: 'Use type predicate', + output: `// Type predicate on "this" class Animal { swim?: Function; isFish(): this is Fish { // Noncompliant @@ -307,13 +308,13 @@ describe('S4322', () => { return !!(this as Fish).swim; } }`, - }, - ], - }, - ], - }, - { - code: `// Method declarations + }, + ], + }, + ], + }, + { + code: `// Method declarations class Farm { isFish(animal: Animal) { // Noncompliant return !!((animal as Fish).swim); @@ -327,13 +328,13 @@ describe('S4322', () => { return !!((animal as Fish).swim); } }`, - errors: [ - { - message: `Declare this function return type using type predicate "animal is Fish".`, - suggestions: [ - { - desc: 'Use type predicate', - output: `// Method declarations + errors: [ + { + message: `Declare this function return type using type predicate "animal is Fish".`, + suggestions: [ + { + desc: 'Use type predicate', + output: `// Method declarations class Farm { isFish(animal: Animal): animal is Fish { // Noncompliant return !!((animal as Fish).swim); @@ -347,41 +348,42 @@ describe('S4322', () => { return !!((animal as Fish).swim); } }`, - }, - ], - }, - ], - }, - { - code: `function isAnimal(animal: Animal) { return Boolean((animal as Fish).swim); }`, - errors: [ - { - messageId: 'useTypePredicate', - suggestions: [ - { - desc: 'Use type predicate', - output: - 'function isAnimal(animal: Animal): animal is Fish { return Boolean((animal as Fish).swim); }', - }, - ], - }, - ], - }, - { - code: `function isAnimal(animal: Animal): boolean { return Boolean((animal as Fish).swim); }`, - errors: [ - { - messageId: 'useTypePredicate', - suggestions: [ - { - desc: 'Use type predicate', - output: - 'function isAnimal(animal: Animal): animal is Fish { return Boolean((animal as Fish).swim); }', - }, - ], - }, - ], - }, - ], + }, + ], + }, + ], + }, + { + code: `function isAnimal(animal: Animal) { return Boolean((animal as Fish).swim); }`, + errors: [ + { + messageId: 'useTypePredicate', + suggestions: [ + { + desc: 'Use type predicate', + output: + 'function isAnimal(animal: Animal): animal is Fish { return Boolean((animal as Fish).swim); }', + }, + ], + }, + ], + }, + { + code: `function isAnimal(animal: Animal): boolean { return Boolean((animal as Fish).swim); }`, + errors: [ + { + messageId: 'useTypePredicate', + suggestions: [ + { + desc: 'Use type predicate', + output: + 'function isAnimal(animal: Animal): animal is Fish { return Boolean((animal as Fish).swim); }', + }, + ], + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4323/unit.test.ts b/packages/jsts/src/rules/S4323/unit.test.ts index a63282e461..2bc9621909 100644 --- a/packages/jsts/src/rules/S4323/unit.test.ts +++ b/packages/jsts/src/rules/S4323/unit.test.ts @@ -16,29 +16,30 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4323', () => { - const ruleTester = new RuleTester(); + it('S4323', () => { + const ruleTester = new RuleTester(); - ruleTester.run('Type aliases should be used', rule, { - valid: [ - { - code: `type MyType = string | null | number;`, - }, - { - code: ` + ruleTester.run('Type aliases should be used', rule, { + valid: [ + { + code: `type MyType = string | null | number;`, + }, + { + code: ` type MyType = string | null | number; const another: MyType | undefined = "";`, - }, - { - code: ` + }, + { + code: ` let x: number | string; let y: number | string; let z: number | string; // this fine because only 2 types in the union`, - }, - { - code: ` + }, + { + code: ` interface A { name: string; a: number; @@ -53,106 +54,107 @@ describe('S4323', () => { name: string; b: number; }`, - }, - { - code: ` + }, + { + code: ` // ok, ignore usage inside type alias type Alias = number | number[] | undefined; function one(x: number | number[] | undefined) {} function two(x: number | number[] | undefined) {}`, - }, - { - code: ` + }, + { + code: ` let x: number | string | undefined; let y: number | string | undefined; let z: number | String | undefined; // this fine because case-sensitive`, - }, - { - code: ` + }, + { + code: ` let x: T | null | undefined; let y: T | null | undefined; let z: T | null | undefined; `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function foo(x: string | null | number) {} const bar: string | null | number = null; function zoo(): string | null | number {} `, - errors: [ - { - message: - '{"message":"Replace this union type with a type alias.","secondaryLocations":[{"message":"Following occurrence.","column":17,"line":3,"endColumn":39,"endLine":3},{"message":"Following occurrence.","column":22,"line":4,"endColumn":44,"endLine":4}]}', - line: 2, - endLine: 2, - column: 23, - endColumn: 45, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: + '{"message":"Replace this union type with a type alias.","secondaryLocations":[{"message":"Following occurrence.","column":17,"line":3,"endColumn":39,"endLine":3},{"message":"Following occurrence.","column":22,"line":4,"endColumn":44,"endLine":4}]}', + line: 2, + endLine: 2, + column: 23, + endColumn: 45, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` function foo(x: string & null & number) {} const bar: string & null & number = null; function zoo(): string & null & number {} `, - errors: [ - { - message: - '{"message":"Replace this intersection type with a type alias.","secondaryLocations":[{"message":"Following occurrence.","column":17,"line":3,"endColumn":39,"endLine":3},{"message":"Following occurrence.","column":22,"line":4,"endColumn":44,"endLine":4}]}', - line: 2, - endLine: 2, - column: 23, - endColumn: 45, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: + '{"message":"Replace this intersection type with a type alias.","secondaryLocations":[{"message":"Following occurrence.","column":17,"line":3,"endColumn":39,"endLine":3},{"message":"Following occurrence.","column":22,"line":4,"endColumn":44,"endLine":4}]}', + line: 2, + endLine: 2, + column: 23, + endColumn: 45, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` let x: string | null | number; let y: number | string | null ; let z: null |number| string ; `, - errors: [ - { - message: - '{"message":"Replace this union type with a type alias.","secondaryLocations":[{"message":"Following occurrence.","column":13,"line":3,"endColumn":35,"endLine":3},{"message":"Following occurrence.","column":15,"line":4,"endColumn":40,"endLine":4}]}', - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: + '{"message":"Replace this union type with a type alias.","secondaryLocations":[{"message":"Following occurrence.","column":13,"line":3,"endColumn":35,"endLine":3},{"message":"Following occurrence.","column":15,"line":4,"endColumn":40,"endLine":4}]}', + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` let x: string & null & number; let y: number & string & null ; let z: null &number& string ; `, - errors: [ - { - message: - '{"message":"Replace this intersection type with a type alias.","secondaryLocations":[{"message":"Following occurrence.","column":13,"line":3,"endColumn":35,"endLine":3},{"message":"Following occurrence.","column":15,"line":4,"endColumn":40,"endLine":4}]}', - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: + '{"message":"Replace this intersection type with a type alias.","secondaryLocations":[{"message":"Following occurrence.","column":13,"line":3,"endColumn":35,"endLine":3},{"message":"Following occurrence.","column":15,"line":4,"endColumn":40,"endLine":4}]}', + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` let x: A | B | C; let y: A | B | C; let z: A | B | C; `, - errors: [ - { - message: - '{"message":"Replace this union type with a type alias.","secondaryLocations":[{"message":"Following occurrence.","column":13,"line":3,"endColumn":22,"endLine":3},{"message":"Following occurrence.","column":13,"line":4,"endColumn":22,"endLine":4}]}', - }, - ], - options: ['sonar-runtime'], - }, - ], + errors: [ + { + message: + '{"message":"Replace this union type with a type alias.","secondaryLocations":[{"message":"Following occurrence.","column":13,"line":3,"endColumn":22,"endLine":3},{"message":"Following occurrence.","column":13,"line":4,"endColumn":22,"endLine":4}]}', + }, + ], + options: ['sonar-runtime'], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4324/unit.test.ts b/packages/jsts/src/rules/S4324/unit.test.ts index d954b7867b..0137bc03f1 100644 --- a/packages/jsts/src/rules/S4324/unit.test.ts +++ b/packages/jsts/src/rules/S4324/unit.test.ts @@ -16,61 +16,62 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4324', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Primitive return types should be used.', rule, { - valid: [ - { - code: `function foo() {return 1;}`, - }, - { - code: `function noReturn(): any {}`, - }, - { - code: `function emptyReturn(): any {return;}`, - }, - { - code: `// OK, returns different primitive types + it('S4324', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Primitive return types should be used.', rule, { + valid: [ + { + code: `function foo() {return 1;}`, + }, + { + code: `function noReturn(): any {}`, + }, + { + code: `function emptyReturn(): any {return;}`, + }, + { + code: `// OK, returns different primitive types function returnUndefined(x: any): any { if (x) { return 1; } return; }`, - }, - { - code: `// OK, returns different primitive types + }, + { + code: `// OK, returns different primitive types function outer(x: any): any { if (x) return ""; function inner(): number {} return 1; }`, - }, - { - code: `// OK, returns union type + }, + { + code: `// OK, returns union type function ternary(x: any): any { const y = x ? 1 : 2; return y; }`, - }, - { - code: `// OK, returns non-primitive type + }, + { + code: `// OK, returns non-primitive type function createObject(): any { return { foo: 1, bar: null }; }`, - }, - { - code: ` + }, + { + code: ` function withInnerFunction(): any { function inner() { return 1; } }`, - }, - { - code: `// ok, returns complex type + }, + { + code: `// ok, returns complex type function returnsSameComplexType(x: any): any { if (x) { return new Date(); @@ -78,9 +79,9 @@ describe('S4324', () => { return new Date(); } }`, - }, - { - code: `// OK, returns any in any case + }, + { + code: `// OK, returns any in any case function returnsAny(x: any, y: any): any { if (x) { return x; @@ -88,55 +89,55 @@ describe('S4324', () => { return y; } }`, - }, - { - code: `class A { + }, + { + code: `class A { isFish(animal: Animal): any { return 1; } }`, - }, - ], - invalid: [ - { - code: `function returnNumericLiteral(): any {return 1;}`, - errors: [ - { - message: 'Remove this return type or change it to a more specific.', - line: 1, - endLine: 1, - column: 32, - endColumn: 37, - }, - ], - }, - { - code: `function returnNumericLiteral(): any {return 1 + 1;}`, - errors: 1, - }, - { - code: `function returnStringLiteral(): any {return "foo";}`, - errors: 1, - }, - { - code: `function returnStringLiteral(): any {return "".substr(1);}`, - errors: 1, - }, - { - code: `function returnBooleanLiteral(): any {return false;}`, - errors: 1, - }, - { - code: `enum E {Foo,} + }, + ], + invalid: [ + { + code: `function returnNumericLiteral(): any {return 1;}`, + errors: [ + { + message: 'Remove this return type or change it to a more specific.', + line: 1, + endLine: 1, + column: 32, + endColumn: 37, + }, + ], + }, + { + code: `function returnNumericLiteral(): any {return 1 + 1;}`, + errors: 1, + }, + { + code: `function returnStringLiteral(): any {return "foo";}`, + errors: 1, + }, + { + code: `function returnStringLiteral(): any {return "".substr(1);}`, + errors: 1, + }, + { + code: `function returnBooleanLiteral(): any {return false;}`, + errors: 1, + }, + { + code: `enum E {Foo,} function returnEnum(): any {return E.Foo;}`, - errors: 1, - }, - { - code: `function returnBooleanLiteral(): any {return 2 > 1;}`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: `function returnBooleanLiteral(): any {return 2 > 1;}`, + errors: 1, + }, + { + code: ` function severalReturnsNumbers(x: any): any { if (x) { return 1 + 2; @@ -144,10 +145,10 @@ describe('S4324', () => { return 3 + 7; } }`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` function severalReturnsStrings(x: string): any { if (x.length > 3) { return x.substr(3); @@ -155,10 +156,10 @@ describe('S4324', () => { return x; } }`, - errors: 1, - }, - { - code: `//Nested functions + errors: 1, + }, + { + code: `//Nested functions function outer(): number { if (false) return -1; function inner(): any { @@ -166,8 +167,9 @@ describe('S4324', () => { } return 0; }`, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4328/unit.test.ts b/packages/jsts/src/rules/S4328/unit.test.ts index c99092293b..d36953e525 100644 --- a/packages/jsts/src/rules/S4328/unit.test.ts +++ b/packages/jsts/src/rules/S4328/unit.test.ts @@ -18,211 +18,212 @@ import path from 'path'; import { NoTypeCheckingRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; import parser from '@typescript-eslint/parser'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4328', () => { - const fixtures = path.join(import.meta.dirname, 'fixtures'); - const filename = path.join(fixtures, 'package-json-project/file.js'); + it('S4328', () => { + const fixtures = path.join(import.meta.dirname, 'fixtures'); + const filename = path.join(fixtures, 'package-json-project/file.js'); - const options = [ - { - whitelist: [], - }, - ]; - const ruleTester = new NoTypeCheckingRuleTester(); - - const filenameNestedPackage = path.join(fixtures, 'nested-package-json-project/dir/file.js'); - - ruleTester.run('Dependencies should be explicit', rule, { - valid: [ - { - code: `import fs from "fs";`, - filename, - options, - }, - { - code: `import ts from "devDependency";`, - filename, - options, - }, - { - code: `import "peerDependency";`, - filename, - options, - }, - { - code: `import "dependency";`, - filename, - options, - }, - { - code: `import "optionalDependency";`, - filename, - options, - }, - { - code: `import "moduleAlias/bla";`, - filename, - options, - }, - { - code: `import "project1";`, - filename, - options, - }, - { - code: `import "@namespaced/dependency";`, - filename, - options, - }, - { - code: `import "typed-dependency";`, - filename, - options, - }, - { - code: `import "whitelist";`, - filename, - options: [{ whitelist: ['whitelist'] }], - }, - { - code: `import "@whitelist/dependency";`, - filename, - options: [{ whitelist: ['@whitelist/dependency'] }], - }, - { - code: `import "./relative";`, - filename, - options, - }, - { - code: `const fs = require("fs");`, - filename, - options, - }, - { - code: `const foo = require("foo", "bar");`, - filename, - options, - }, - { - code: `import "dependency";`, - filename: path.join(fixtures, 'bom-package-json-project/file.js'), - options, - }, - { - code: `const fs = require("node:fs/promises");`, - filename, - options, - }, - { - code: `import fs from 'node:fs/promises';`, - filename, - options, - }, - { - code: `import 'data:text/javascript,console.log("hello, world!");';`, - filename, - options, - }, + const options = [ { - code: `import 'file:/some/file.js'`, - filename, - options, + whitelist: [], }, - { - code: ` + ]; + const ruleTester = new NoTypeCheckingRuleTester(); + + const filenameNestedPackage = path.join(fixtures, 'nested-package-json-project/dir/file.js'); + + ruleTester.run('Dependencies should be explicit', rule, { + valid: [ + { + code: `import fs from "fs";`, + filename, + options, + }, + { + code: `import ts from "devDependency";`, + filename, + options, + }, + { + code: `import "peerDependency";`, + filename, + options, + }, + { + code: `import "dependency";`, + filename, + options, + }, + { + code: `import "optionalDependency";`, + filename, + options, + }, + { + code: `import "moduleAlias/bla";`, + filename, + options, + }, + { + code: `import "project1";`, + filename, + options, + }, + { + code: `import "@namespaced/dependency";`, + filename, + options, + }, + { + code: `import "typed-dependency";`, + filename, + options, + }, + { + code: `import "whitelist";`, + filename, + options: [{ whitelist: ['whitelist'] }], + }, + { + code: `import "@whitelist/dependency";`, + filename, + options: [{ whitelist: ['@whitelist/dependency'] }], + }, + { + code: `import "./relative";`, + filename, + options, + }, + { + code: `const fs = require("fs");`, + filename, + options, + }, + { + code: `const foo = require("foo", "bar");`, + filename, + options, + }, + { + code: `import "dependency";`, + filename: path.join(fixtures, 'bom-package-json-project/file.js'), + options, + }, + { + code: `const fs = require("node:fs/promises");`, + filename, + options, + }, + { + code: `import fs from 'node:fs/promises';`, + filename, + options, + }, + { + code: `import 'data:text/javascript,console.log("hello, world!");';`, + filename, + options, + }, + { + code: `import 'file:/some/file.js'`, + filename, + options, + }, + { + code: ` import { f as f1 } from 'top-dependency'; import { f as f2 } from 'nested-dependency'; import { f as f2 } from 'local-dependency'; `, - filename: filenameNestedPackage, - options, - }, - ], - invalid: [ - { - code: `import "foo";`, - filename, - options, - errors: [ - { - message: 'Either remove this import or add it as a dependency.', - line: 1, - endLine: 1, - column: 1, - endColumn: 7, - }, - ], - }, - { - code: `let foo = require("foo");`, - filename, - options, - errors: [ - { - message: 'Either remove this import or add it as a dependency.', - line: 1, - endLine: 1, - column: 11, - endColumn: 18, - }, - ], - }, - { - code: `import "foo/bar";`, - filename, - options, - errors: 1, - }, - { - code: `import "foo";`, - filename: path.join(fixtures, 'empty-package-json-project/file.js'), - options, - errors: 1, - }, - { - code: `import "foo";`, - filename: path.join(fixtures, 'package-json-project/dir/subdir/file.js'), - options, - errors: 1, - }, - { - code: `import "foo";`, - filename: '/file.js', - options, - errors: 1, - }, - { - code: ` + filename: filenameNestedPackage, + options, + }, + ], + invalid: [ + { + code: `import "foo";`, + filename, + options, + errors: [ + { + message: 'Either remove this import or add it as a dependency.', + line: 1, + endLine: 1, + column: 1, + endColumn: 7, + }, + ], + }, + { + code: `let foo = require("foo");`, + filename, + options, + errors: [ + { + message: 'Either remove this import or add it as a dependency.', + line: 1, + endLine: 1, + column: 11, + endColumn: 18, + }, + ], + }, + { + code: `import "foo/bar";`, + filename, + options, + errors: 1, + }, + { + code: `import "foo";`, + filename: path.join(fixtures, 'empty-package-json-project/file.js'), + options, + errors: 1, + }, + { + code: `import "foo";`, + filename: path.join(fixtures, 'package-json-project/dir/subdir/file.js'), + options, + errors: 1, + }, + { + code: `import "foo";`, + filename: '/file.js', + options, + errors: 1, + }, + { + code: ` import { f as f1 } from 'nonexistent'; `, - filename: filenameNestedPackage, - options, - errors: 1, - }, - ], - }); + filename: filenameNestedPackage, + options, + errors: 1, + }, + ], + }); - const ruleTesterForPathMappings = new RuleTester({ - parser, - ecmaVersion: 2018, - sourceType: 'module', - parserOptions: { - tsconfigRootDir: path.join(fixtures, 'ts-project-with-path-aliases'), - project: './tsconfig.json', - }, - }); + const ruleTesterForPathMappings = new RuleTester({ + parser, + ecmaVersion: 2018, + sourceType: 'module', + parserOptions: { + tsconfigRootDir: path.join(fixtures, 'ts-project-with-path-aliases'), + project: './tsconfig.json', + }, + }); - const filenameForFileWithPathMappings = path.join( - fixtures, - 'ts-project-with-path-aliases/file.ts', - ); + const filenameForFileWithPathMappings = path.join( + fixtures, + 'ts-project-with-path-aliases/file.ts', + ); - ruleTesterForPathMappings.run('Path aliases should be exempt', rule, { - valid: [ - { - code: ` + ruleTesterForPathMappings.run('Path aliases should be exempt', rule, { + valid: [ + { + code: ` import { f as f1 } from '$b/c/d.e'; import { f as f2 } from '@b/c/d.e'; import { f as f3 } from 'b/c/d.e'; @@ -233,13 +234,13 @@ describe('S4328', () => { import { f as f8 } from 'yoda/c/d.e/path'; import { f as f9 } from 'dependency-in-package-json'; `, - filename: filenameForFileWithPathMappings, - options, - }, - ], - invalid: [ - { - code: ` + filename: filenameForFileWithPathMappings, + options, + }, + ], + invalid: [ + { + code: ` import { f as f1 } from '$invalid/c/d.e'; import { f as f2 } from '@invalid/c/d.e'; import { f as f3 } from 'invalid/c/d.e'; @@ -251,49 +252,50 @@ describe('S4328', () => { import { f as f9 } from 'yoda/c/d.e/paths'; import { f as fA } from 'dependency-not-in-package-json'; `, - filename: filenameForFileWithPathMappings, - options, - errors: 10, - }, - ], - }); + filename: filenameForFileWithPathMappings, + options, + errors: 10, + }, + ], + }); - const ruleTesterForBaseUrl = new RuleTester({ - parser, - ecmaVersion: 2018, - sourceType: 'module', - parserOptions: { - tsconfigRootDir: path.join(fixtures, 'ts-project-with-base-url'), - project: './tsconfig.json', - }, - }); + const ruleTesterForBaseUrl = new RuleTester({ + parser, + ecmaVersion: 2018, + sourceType: 'module', + parserOptions: { + tsconfigRootDir: path.join(fixtures, 'ts-project-with-base-url'), + project: './tsconfig.json', + }, + }); - const filenameForBaseUrl = path.join(fixtures, 'ts-project-with-base-url/nested/file.ts'); + const filenameForBaseUrl = path.join(fixtures, 'ts-project-with-base-url/nested/file.ts'); - ruleTesterForBaseUrl.run('Imports based on baseUrl should be accepted', rule, { - valid: [ - { - code: ` + ruleTesterForBaseUrl.run('Imports based on baseUrl should be accepted', rule, { + valid: [ + { + code: ` import { f as f1 } from 'dependency-in-package-json'; import { f as f2 } from 'dir'; import { f as f3 } from 'a'; import { f as f3 } from 'c'; import { f as f4 } from 'dir/b'; `, - filename: filenameForBaseUrl, - options, - }, - ], - invalid: [ - { - code: ` + filename: filenameForBaseUrl, + options, + }, + ], + invalid: [ + { + code: ` import { f as f1 } from 'nonexistent'; import { f as f1 } from 'dir/nonexistent'; `, - filename: filenameForBaseUrl, - options, - errors: 2, - }, - ], + filename: filenameForBaseUrl, + options, + errors: 2, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4335/unit.test.ts b/packages/jsts/src/rules/S4335/unit.test.ts index 1b18f8aea0..80829d9c61 100644 --- a/packages/jsts/src/rules/S4335/unit.test.ts +++ b/packages/jsts/src/rules/S4335/unit.test.ts @@ -16,32 +16,33 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4335', () => { - const ruleTester = new RuleTester(); - ruleTester.run( - `Types without members, 'any' and 'never' should not be used in type intersections`, - rule, - { - valid: [ - { - code: `function twoPrimitives(x: string & number) {}`, - }, - { - code: `function twoInterfaces(x: { a: string } & { b: number }) {}`, - }, - { - code: ` + it('S4335', () => { + const ruleTester = new RuleTester(); + ruleTester.run( + `Types without members, 'any' and 'never' should not be used in type intersections`, + rule, + { + valid: [ + { + code: `function twoPrimitives(x: string & number) {}`, + }, + { + code: `function twoInterfaces(x: { a: string } & { b: number }) {}`, + }, + { + code: ` interface WithString { a: string; } interface NotEmpty extends WithString {} function withNotEmptyInterface(x: { a: string } & NotEmpty) {} `, - }, - { - code: ` + }, + { + code: ` const propName = 'prop-name'; interface MyInterface { @@ -54,9 +55,9 @@ describe('S4335', () => { type MyType = MyOtherInterface & MyInterface; `, - }, - { - code: ` + }, + { + code: ` export namespace TestCaseParser { export interface CompilerSettings { [name: string]: string; @@ -73,9 +74,9 @@ describe('S4335', () => { let harnessSettings: TestCaseParser.CompilerSettings & HarnessOptions; `, - }, - { - code: ` + }, + { + code: ` export namespace TestCaseParser { export interface CompilerSettings { [name: number]: string; @@ -92,61 +93,62 @@ describe('S4335', () => { let harnessSettings: TestCaseParser.CompilerSettings & HarnessOptions; `, - }, - ], - invalid: [ - { - code: `function withNull(x: number & null) {}`, - errors: [ - { - message: 'Remove this type without members or change this type intersection.', - line: 1, - column: 31, - endLine: 1, - endColumn: 35, - }, - ], - }, - { - code: `function withAny(x: any & { a: string }) {}`, - errors: [{ message: `Simplify this intersection as it always has type "any".` }], - }, - { - code: `function withNever(x: boolean & never) {}`, - errors: [{ message: `Simplify this intersection as it always has type "never".` }], - }, - { - code: `function withUndefined(x: { a: string } & undefined) {}`, - errors: 1, - }, - { - code: `function withVoid(x: string & void) {}`, - errors: 1, - }, - { - code: `function triple(x: null & string & undefined) {}`, - errors: 2, - }, - { - code: ` + }, + ], + invalid: [ + { + code: `function withNull(x: number & null) {}`, + errors: [ + { + message: 'Remove this type without members or change this type intersection.', + line: 1, + column: 31, + endLine: 1, + endColumn: 35, + }, + ], + }, + { + code: `function withAny(x: any & { a: string }) {}`, + errors: [{ message: `Simplify this intersection as it always has type "any".` }], + }, + { + code: `function withNever(x: boolean & never) {}`, + errors: [{ message: `Simplify this intersection as it always has type "never".` }], + }, + { + code: `function withUndefined(x: { a: string } & undefined) {}`, + errors: 1, + }, + { + code: `function withVoid(x: string & void) {}`, + errors: 1, + }, + { + code: `function triple(x: null & string & undefined) {}`, + errors: 2, + }, + { + code: ` function declarations() { let x: string & null; } `, - errors: 1, - }, - { - code: `function withEmptyObjectLiteral(x: { a: string } & {}) {}`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: `function withEmptyObjectLiteral(x: { a: string } & {}) {}`, + errors: 1, + }, + { + code: ` interface Empty {} function withEmptyInterface(x: { a: string } & Empty) {} `, - errors: 1, - }, - ], - }, - ); + errors: 1, + }, + ], + }, + ); + }); }); diff --git a/packages/jsts/src/rules/S4423/unit.test.ts b/packages/jsts/src/rules/S4423/unit.test.ts index f75c840d88..24af842a4c 100644 --- a/packages/jsts/src/rules/S4423/unit.test.ts +++ b/packages/jsts/src/rules/S4423/unit.test.ts @@ -16,15 +16,16 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4423', () => { - const ruleTesterJs = new RuleTester(); + it('S4423', () => { + const ruleTesterJs = new RuleTester(); - const minMaxVersion = { - valid: [ - { - code: ` + const minMaxVersion = { + valid: [ + { + code: ` const tls = require('tls'); const constants = require('constants'); tls.connect({ @@ -42,21 +43,21 @@ describe('S4423', () => { maxVersion: 'TLSv1.3' }); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const tls = require('node:tls'); const constants = require('constants'); tls.connect({ minVersion: 'TLSv1.1', }); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const tls = require('tls'); const constants = require('constants'); tls.connect({ @@ -64,18 +65,18 @@ describe('S4423', () => { maxVersion: 'TLSv1.2' }); `, - errors: [ - { - message: "Change 'minVersion' to use at least TLS v1.2.", - line: 5, - column: 21, - endLine: 5, - endColumn: 30, - }, - ], - }, - { - code: ` + errors: [ + { + message: "Change 'minVersion' to use at least TLS v1.2.", + line: 5, + column: 21, + endLine: 5, + endColumn: 30, + }, + ], + }, + { + code: ` const tls = require('tls'); const constants = require('constants'); tls.connect({ @@ -91,10 +92,10 @@ describe('S4423', () => { maxVersion: 'TLSv1.1' }); `, - errors: 4, - }, - { - code: ` + errors: 4, + }, + { + code: ` const https = require('https'); const constants = require('constants'); @@ -105,25 +106,25 @@ describe('S4423', () => { var req23 = https.request(options23); `, - errors: [ - { - message: "Change 'minVersion' to use at least TLS v1.2.", - line: 6, - column: 21, - endLine: 6, - endColumn: 30, - }, - { - message: "Change 'maxVersion' to use at least TLS v1.2.", - line: 7, - column: 21, - endLine: 7, - endColumn: 30, - }, - ], - }, - { - code: ` + errors: [ + { + message: "Change 'minVersion' to use at least TLS v1.2.", + line: 6, + column: 21, + endLine: 6, + endColumn: 30, + }, + { + message: "Change 'maxVersion' to use at least TLS v1.2.", + line: 7, + column: 21, + endLine: 7, + endColumn: 30, + }, + ], + }, + { + code: ` const https = require('node:https'); const constants = require('node:constants'); @@ -134,10 +135,10 @@ describe('S4423', () => { var req23 = https.request(options23); `, - errors: 2, - }, - { - code: ` + errors: 2, + }, + { + code: ` const request = require('request'); const constants = require('constants'); @@ -147,15 +148,15 @@ describe('S4423', () => { maxVersion: 'TLSv1.1' // Noncompliant }); // Noncompliant `, - errors: 2, - }, - ], - }; + errors: 2, + }, + ], + }; - const secureProtocol = { - valid: [ - { - code: ` + const secureProtocol = { + valid: [ + { + code: ` const request = require('request'); const constants = require('constants'); @@ -165,9 +166,9 @@ describe('S4423', () => { secureProtocol: 'TLSv1_2_method' // Compliant }); `, - }, - { - code: ` + }, + { + code: ` const https = require('https'); var options17 = { @@ -186,11 +187,11 @@ describe('S4423', () => { process.stdout.write(d); }); }); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const https = require('https'); const constants = require('constants'); var options5 = { @@ -199,18 +200,18 @@ describe('S4423', () => { var req5 = https.request(options5); `, - errors: [ - { - message: "Change 'secureProtocol' to use at least TLS v1.2.", - line: 5, - column: 25, - endLine: 5, - endColumn: 39, - }, - ], - }, - { - code: ` + errors: [ + { + message: "Change 'secureProtocol' to use at least TLS v1.2.", + line: 5, + column: 25, + endLine: 5, + endColumn: 39, + }, + ], + }, + { + code: ` const request = require('request'); const constants = require('constants'); @@ -219,15 +220,15 @@ describe('S4423', () => { secureProtocol: 'DTLSv1_client_method' // Noncompliant }); `, - errors: 1, - }, - ], - }; + errors: 1, + }, + ], + }; - const secureOptions = { - valid: [ - { - code: ` + const secureOptions = { + valid: [ + { + code: ` var options3 = { hostname: 'www.google.com', port: 443, @@ -245,9 +246,9 @@ describe('S4423', () => { }); }); // Compliant `, - }, - { - code: ` + }, + { + code: ` const https = require('https'); const constants = require('constants'); @@ -268,11 +269,11 @@ describe('S4423', () => { }); }); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const https = require('https'); const constants = require('constants'); @@ -293,18 +294,18 @@ describe('S4423', () => { }); }); `, - errors: [ - { - line: 10, - column: 9, - endLine: 10, - endColumn: 105, - message: "Change 'secureOptions' to allow only secure TLS versions.", - }, - ], - }, - { - code: ` + errors: [ + { + line: 10, + column: 9, + endLine: 10, + endColumn: 105, + message: "Change 'secureOptions' to allow only secure TLS versions.", + }, + ], + }, + { + code: ` const tls = require('tls'); const constants = require('constants'); var options1 = { @@ -313,10 +314,10 @@ describe('S4423', () => { tls.createSecureContext(options1); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const tls = require('tls'); const c = require('constants'); var options1 = { @@ -325,12 +326,13 @@ describe('S4423', () => { tls.createSecureContext(options1); `, - errors: 1, - }, - ], - }; + errors: 1, + }, + ], + }; - ruleTesterJs.run('Should use strong TLS: minMaxVersion', rule, minMaxVersion); - ruleTesterJs.run('Should use strong TLS: secureProtocol', rule, secureProtocol); - ruleTesterJs.run('Should use strong TLS: secureOptions', rule, secureOptions); + ruleTesterJs.run('Should use strong TLS: minMaxVersion', rule, minMaxVersion); + ruleTesterJs.run('Should use strong TLS: secureProtocol', rule, secureProtocol); + ruleTesterJs.run('Should use strong TLS: secureOptions', rule, secureOptions); + }); }); diff --git a/packages/jsts/src/rules/S4426/unit.test.ts b/packages/jsts/src/rules/S4426/unit.test.ts index 1a53be56d1..4c482b0280 100644 --- a/packages/jsts/src/rules/S4426/unit.test.ts +++ b/packages/jsts/src/rules/S4426/unit.test.ts @@ -16,24 +16,25 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4426', () => { - const ruleTesterJS = new RuleTester(); + it('S4426', () => { + const ruleTesterJS = new RuleTester(); - ruleTesterJS.run('Cryptographic keys should be robust', rule, { - valid: [ - { - code: ` + ruleTesterJS.run('Cryptographic keys should be robust', rule, { + valid: [ + { + code: ` crypto.generateKeyPair('rsa', { modulusLength: 2048, // Compliant publicKeyEncoding: { type: 'spki', format: 'pem' }, privateKeyEncoding: { type: 'pkcs8', format: 'pem' } }, callback); `, - }, - { - code: ` + }, + { + code: ` // adding coverage crypto.generateKeyPair('ed25519', { // unrelated algorithm modulusLength: 1, // Compliant @@ -45,9 +46,9 @@ describe('S4426', () => { crypto.generateKeyPair('ed25519', options()); // options not an ObjectExpression crypto.generateKeyPair(alg(), {}); // algorithm not Literal `, - }, - { - code: ` + }, + { + code: ` const alg = 'ed25519'; crypto.generateKeyPair(alg, { // alg not literal modulusLength: 1, // Compliant @@ -55,47 +56,47 @@ describe('S4426', () => { privateKeyEncoding: { type: 'pkcs8', format: 'pem' } }, callback); `, - }, - { - code: ` + }, + { + code: ` crypto.generateKeyPair('dsa', { divisorLength: 224, // Compliant publicKeyEncoding: { type: 'spki', format: 'pem' }, privateKeyEncoding: { type: 'pkcs8', format: 'pem' } }, callback); `, - }, - { - code: ` + }, + { + code: ` crypto.generateKeyPair('ec', { namedCurve: 'secp224k1', publicKeyEncoding: { type: 'spki', format: 'pem' }, privateKeyEncoding: { type: 'pkcs8', format: 'pem' } }, callback); // compliant `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` var { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', { modulusLength: 1024, // Noncompliant publicKeyEncoding: { type: 'spki', format: 'pem' }, privateKeyEncoding: { type: 'pkcs8', format: 'pem' } }); // Noncompliant: 1024 bits is too short for a RSA key pair `, - errors: [ - { - message: `Use a modulus length of at least 2048 bits for rsa cipher algorithm.`, - line: 3, - endLine: 3, - column: 11, - endColumn: 30, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Use a modulus length of at least 2048 bits for rsa cipher algorithm.`, + line: 3, + endLine: 3, + column: 11, + endColumn: 30, + }, + ], + }, + { + code: ` const alg = 'rsa'; var { privateKey, publicKey } = crypto.generateKeyPairSync(alg, { modulusLength: 1024, // Noncompliant @@ -103,18 +104,18 @@ describe('S4426', () => { privateKeyEncoding: { type: 'pkcs8', format: 'pem' } }); // Noncompliant: 1024 bits is too short for a RSA key pair `, - errors: [ - { - message: `Use a modulus length of at least 2048 bits for rsa cipher algorithm.`, - line: 4, - endLine: 4, - column: 11, - endColumn: 30, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Use a modulus length of at least 2048 bits for rsa cipher algorithm.`, + line: 4, + endLine: 4, + column: 11, + endColumn: 30, + }, + ], + }, + { + code: ` var options = { modulusLength: 1024, // Noncompliant publicKeyEncoding: { type: 'spki', format: 'pem' }, @@ -123,36 +124,36 @@ describe('S4426', () => { var { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', options); // Noncompliant `, - errors: [ - { - message: `Use a modulus length of at least 2048 bits for rsa cipher algorithm.`, - line: 3, - endLine: 3, - column: 11, - endColumn: 30, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Use a modulus length of at least 2048 bits for rsa cipher algorithm.`, + line: 3, + endLine: 3, + column: 11, + endColumn: 30, + }, + ], + }, + { + code: ` var { privateKey, publicKey } = crypto.generateKeyPairSync('dsa', { modulusLength: 1024, // Noncompliant publicKeyEncoding: { type: 'spki', format: 'pem' }, privateKeyEncoding: { type: 'pkcs8', format: 'pem' } }); // Noncompliant: 1024 bits is too short for a RSA key pair `, - errors: [ - { - message: `Use a modulus length of at least 2048 bits for dsa cipher algorithm.`, - line: 3, - endLine: 3, - column: 11, - endColumn: 30, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Use a modulus length of at least 2048 bits for dsa cipher algorithm.`, + line: 3, + endLine: 3, + column: 11, + endColumn: 30, + }, + ], + }, + { + code: ` crypto.generateKeyPair('dsa', { modulusLength: 2048, // Compliant divisorLength: 112, // Noncompliant @@ -160,18 +161,18 @@ describe('S4426', () => { privateKeyEncoding: { type: 'pkcs8', format: 'pem' } }, callback); // Noncompliant `, - errors: [ - { - message: `Use a divisor length of at least 224 bits for dsa cipher algorithm.`, - line: 4, - endLine: 4, - column: 11, - endColumn: 29, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Use a divisor length of at least 224 bits for dsa cipher algorithm.`, + line: 4, + endLine: 4, + column: 11, + endColumn: 29, + }, + ], + }, + { + code: ` const crypto = require('crypto'); crypto.generateKeyPair('ec', { namedCurve: 'secp112r2', @@ -179,16 +180,17 @@ describe('S4426', () => { privateKeyEncoding: { type: 'pkcs8', format: 'pem' } }, callback); // Noncompliant: secp112r2 curve doesn't provide enough security `, - errors: [ - { - message: `secp112r2 doesn't provide enough security. Use a stronger curve.`, - line: 4, - endLine: 4, - column: 11, - endColumn: 34, - }, - ], - }, - ], + errors: [ + { + message: `secp112r2 doesn't provide enough security. Use a stronger curve.`, + line: 4, + endLine: 4, + column: 11, + endColumn: 34, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4502/unit.test.ts b/packages/jsts/src/rules/S4502/unit.test.ts index 1f2faab3ed..63c4ae2ce5 100644 --- a/packages/jsts/src/rules/S4502/unit.test.ts +++ b/packages/jsts/src/rules/S4502/unit.test.ts @@ -16,15 +16,16 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4502', () => { - const ruleTester = new RuleTester(); + it('S4502', () => { + const ruleTester = new RuleTester(); - ruleTester.run('Disabling CSRF protections is security-sensitive', rule, { - valid: [ - { - code: ` + ruleTester.run('Disabling CSRF protections is security-sensitive', rule, { + valid: [ + { + code: ` var app = express(); var csrf = require('csurf'); var csrfProtection = csrf({ cookie: { httpOnly: true, secure:true }}) @@ -34,24 +35,24 @@ describe('S4502', () => { res.send('data is being processed') }); `, - }, - { - code: ` + }, + { + code: ` var app = express(); var csrf = require('csurf'); var csrfProtection = csrf({ cookie: { httpOnly: true, secure:true}, ignoreMethods: [] }); var csrfProtection2 = csrf({ cookie: { httpOnly: true, secure:true}, ignoreMethods: bar() }); `, - }, - { - code: ` + }, + { + code: ` app.post('/process', function (req, res) { // ok as 'csurf' is not imported res.send('data is being processed'); }); `, - }, - { - code: ` + }, + { + code: ` var app = express(); var csrf = require('csurf'); var csrfProtection = csrf({ cookie: { httpOnly: true, secure:true }}) @@ -65,33 +66,33 @@ describe('S4502', () => { res.send('data is being processed') }); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` var app = express(); var csrf = require('csurf'); var csrfProtection = csrf({ cookie: { httpOnly: true, secure:true}, ignoreMethods: ["POST", "PUT", "GET"] }); // Sensitive `, - errors: [ - { - message: encodedMessage('Make sure disabling CSRF protection is safe here.', { + errors: [ + { + message: encodedMessage('Make sure disabling CSRF protection is safe here.', { + line: 4, + column: 98, + endColumn: 103, + endLine: 4, + }), line: 4, - column: 98, - endColumn: 103, endLine: 4, - }), - line: 4, - endLine: 4, - column: 91, - endColumn: 97, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + column: 91, + endColumn: 97, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` var app = express(); var csrf = require('csurf'); var csrfProtection = csrf({ cookie: { httpOnly: true, secure:true }}) @@ -100,62 +101,63 @@ describe('S4502', () => { res.send('data is being processed') }) `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` var csrf = require('csurf'); app.post('/process', function (req, res) { // Sensitive: csrf used after res.send('data is being processed'); }); app.use(csrf({ cookie: true })); `, - errors: [ - { - line: 3, - endLine: 3, - column: 9, - endColumn: 17, - message: encodedMessage('Make sure not using CSRF protection is safe here.'), - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + line: 3, + endLine: 3, + column: 9, + endColumn: 17, + message: encodedMessage('Make sure not using CSRF protection is safe here.'), + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` import csrf from 'csurf'; app.post('/process', function (req, res) { res.send('data is being processed'); }); `, - errors: [ + errors: [ + { + message: 'Make sure not using CSRF protection is safe here.', + line: 3, + }, + ], + }, + ], + }); + + function encodedMessage( + message: string, + secondary?: { line: number; column: number; endColumn: number; endLine: number }, + ) { + let secondaryLocations = []; + if (secondary) { + secondaryLocations = [ { - message: 'Make sure not using CSRF protection is safe here.', - line: 3, + column: secondary.column, + line: secondary.line, + endColumn: secondary.endColumn, + endLine: secondary.endLine, }, - ], - }, - ], - }); - - function encodedMessage( - message: string, - secondary?: { line: number; column: number; endColumn: number; endLine: number }, - ) { - let secondaryLocations = []; - if (secondary) { - secondaryLocations = [ - { - column: secondary.column, - line: secondary.line, - endColumn: secondary.endColumn, - endLine: secondary.endLine, - }, - ]; + ]; + } + return JSON.stringify({ + message, + secondaryLocations, + }); } - return JSON.stringify({ - message, - secondaryLocations, - }); - } + }); }); diff --git a/packages/jsts/src/rules/S4507/unit.test.ts b/packages/jsts/src/rules/S4507/unit.test.ts index dd66d1306b..5044ec40f2 100644 --- a/packages/jsts/src/rules/S4507/unit.test.ts +++ b/packages/jsts/src/rules/S4507/unit.test.ts @@ -16,21 +16,22 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4507', () => { - const ruleTester = new RuleTester(); + it('S4507', () => { + const ruleTester = new RuleTester(); - const message = - 'Make sure this debug feature is deactivated before delivering the code in production.'; + const message = + 'Make sure this debug feature is deactivated before delivering the code in production.'; - ruleTester.run( - 'Delivering code in production with debug features activated is security-sensitive', - rule, - { - valid: [ - { - code: ` + ruleTester.run( + 'Delivering code in production with debug features activated is security-sensitive', + rule, + { + valid: [ + { + code: ` Debug.write("hello, world"); // we report only on trivial (and mostly used) usages without object access @@ -44,38 +45,38 @@ describe('S4507', () => { import { confirm } from './confirm'; confirm("Are you sure?"); `, - }, - { - code: ` + }, + { + code: ` alert("here!"); confirm("Are you sure?"); prompt("What's your name?", "John Doe"); `, - }, - { - code: `debugger;`, - }, - ], - invalid: [ - { - code: ` + }, + { + code: `debugger;`, + }, + ], + invalid: [ + { + code: ` const errorhandler = require('errorhandler'); if (process.env.NODE_ENV === 'development') { app1.use(errorhandler()); // Compliant } app2.use(errorhandler()); // Noncompliant `, - errors: [ - { - message, - line: 6, - column: 18, - endColumn: 32, - }, - ], - }, - { - code: ` + errors: [ + { + message, + line: 6, + column: 18, + endColumn: 32, + }, + ], + }, + { + code: ` import errorhandler from 'errorhandler'; const handler = errorhandler(); app1.use(handler); // Noncompliant @@ -86,17 +87,17 @@ describe('S4507', () => { } app4.use(); `, - errors: [ - { - message, - line: 3, - column: 25, - endColumn: 39, - }, - ], - }, - { - code: ` + errors: [ + { + message, + line: 3, + column: 25, + endColumn: 39, + }, + ], + }, + { + code: ` const errorhandler = require('errorhandler'); const middlewares = [ helmet(), @@ -104,16 +105,17 @@ describe('S4507', () => { ]; app2.use(sth, middlewares, sthElse); // Noncompliant `, - errors: [ - { - message, - line: 5, - column: 11, - endColumn: 25, - }, - ], - }, - ], - }, - ); + errors: [ + { + message, + line: 5, + column: 11, + endColumn: 25, + }, + ], + }, + ], + }, + ); + }); }); diff --git a/packages/jsts/src/rules/S4524/unit.test.ts b/packages/jsts/src/rules/S4524/unit.test.ts index 4332429852..81c857f04c 100644 --- a/packages/jsts/src/rules/S4524/unit.test.ts +++ b/packages/jsts/src/rules/S4524/unit.test.ts @@ -16,17 +16,18 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4524', () => { - const ruleTester = new RuleTester(); - ruleTester.run('"default" clauses should be last', rule, { - valid: [ - { - code: `switch (true) {}`, - }, - { - code: ` + it('S4524', () => { + const ruleTester = new RuleTester(); + ruleTester.run('"default" clauses should be last', rule, { + valid: [ + { + code: `switch (true) {}`, + }, + { + code: ` switch (z) { case "foo": console.log("Hello World") @@ -37,19 +38,19 @@ describe('S4524', () => { default: console.log("Default message"); }`, - }, - { - code: ` + }, + { + code: ` switch (z) { case "foo": console.log("Hello World") break; }`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` switch (x) { case 1: console.log("1"); @@ -58,19 +59,19 @@ describe('S4524', () => { case 2: console.log("2"); }`, - errors: [ - { - message: 'Move this "default" clause to the end of this "switch" statement.', - line: 5, - endLine: 5, - column: 11, - endColumn: 18, - }, - ], - }, + errors: [ + { + message: 'Move this "default" clause to the end of this "switch" statement.', + line: 5, + endLine: 5, + column: 11, + endColumn: 18, + }, + ], + }, - { - code: ` + { + code: ` switch (y) { default: //Nomcompliant console.log("Default message"); @@ -82,8 +83,9 @@ describe('S4524', () => { console.log("42"); break; }`, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4619/unit.test.ts b/packages/jsts/src/rules/S4619/unit.test.ts index aeb3c60923..a24a0ec855 100644 --- a/packages/jsts/src/rules/S4619/unit.test.ts +++ b/packages/jsts/src/rules/S4619/unit.test.ts @@ -16,110 +16,112 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4619', () => { - const ruleTester = new RuleTester(); + it('S4619', () => { + const ruleTester = new RuleTester(); - ruleTester.run('"in" should not be used on arrays"', rule, { - valid: [ - { - code: `const dict = {a: 1, b: 2, c: 3}; + ruleTester.run('"in" should not be used on arrays"', rule, { + valid: [ + { + code: `const dict = {a: 1, b: 2, c: 3}; "a" in dict; // OK on objects`, - }, - { - code: `function okOnArrayLikeObjects(a: any, b: any) { + }, + { + code: `function okOnArrayLikeObjects(a: any, b: any) { let key = "1"; if (key in arguments) { return "Something"; } return "Something else"; }`, - }, - { - code: ` + }, + { + code: ` let x = 'indexOf' in Array.prototype; `, - }, - { - code: ` + }, + { + code: ` var a = []; for (var i = 0, l = a.length; i < l; i++) { if (i in a) { console.log() } }`, - }, - ], - invalid: [ - { - code: `// to check the property of an object do this + }, + ], + invalid: [ + { + code: `// to check the property of an object do this "car" in { "car" : 1}; // and not this "car" in Object.keys({ "car": 1 }); // Noncompliant`, - errors: [ - { - message: `Use "indexOf" or "includes" (available from ES2016) instead.`, - line: 4, - column: 17, - endLine: 4, - endColumn: 51, - suggestions: [ - { - desc: 'Replace with "indexOf" method', - output: `// to check the property of an object do this + errors: [ + { + message: `Use "indexOf" or "includes" (available from ES2016) instead.`, + line: 4, + column: 17, + endLine: 4, + endColumn: 51, + suggestions: [ + { + desc: 'Replace with "indexOf" method', + output: `// to check the property of an object do this "car" in { "car" : 1}; // and not this Object.keys({ "car": 1 }).indexOf("car") > -1; // Noncompliant`, - }, - { - desc: 'Replace with "includes" method', - output: `// to check the property of an object do this + }, + { + desc: 'Replace with "includes" method', + output: `// to check the property of an object do this "car" in { "car" : 1}; // and not this Object.keys({ "car": 1 }).includes("car"); // Noncompliant`, - }, - ], - }, - ], - }, - { - code: `let arr = ["a", "b", "c"]; + }, + ], + }, + ], + }, + { + code: `let arr = ["a", "b", "c"]; "1" in arr; // Noncompliant 1 in arr; "b" in arr; // Noncompliant`, - errors: 2, - }, - { - code: `// in different contexts + errors: 2, + }, + { + code: `// in different contexts let arr = ["a", "b", "c"]; const result = "car" in arr ? "something" : "something else"; // Noncompliant foo("car" in arr); // Noncompliant if ("car" in arr) {} // Noncompliant`, - errors: 3, - }, - { - code: `function erroneousIncludesES2016(array: any[], elem: any) { + errors: 3, + }, + { + code: `function erroneousIncludesES2016(array: any[], elem: any) { return elem in array; // Noncompliant }`, - errors: 1, - }, - { - code: `if ("bar" in ["foo", "bar", "baz"]) {}`, - errors: [ - { - messageId: 'inMisuse', - suggestions: [ - { - desc: `Replace with "indexOf" method`, - output: `if (["foo", "bar", "baz"].indexOf("bar") > -1) {}`, - }, - { - desc: `Replace with "includes" method`, - output: `if (["foo", "bar", "baz"].includes("bar")) {}`, - }, - ], - }, - ], - }, - ], + errors: 1, + }, + { + code: `if ("bar" in ["foo", "bar", "baz"]) {}`, + errors: [ + { + messageId: 'inMisuse', + suggestions: [ + { + desc: `Replace with "indexOf" method`, + output: `if (["foo", "bar", "baz"].indexOf("bar") > -1) {}`, + }, + { + desc: `Replace with "includes" method`, + output: `if (["foo", "bar", "baz"].includes("bar")) {}`, + }, + ], + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4621/unit.test.ts b/packages/jsts/src/rules/S4621/unit.test.ts index 974b20fa72..6c70c4a9fa 100644 --- a/packages/jsts/src/rules/S4621/unit.test.ts +++ b/packages/jsts/src/rules/S4621/unit.test.ts @@ -16,18 +16,19 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4621', () => { - const ruleTester = new RuleTester(); + it('S4621', () => { + const ruleTester = new RuleTester(); - ruleTester.run( - 'Union and intersection types should not be defined with duplicated elements', - rule, - { - valid: [ - { - code: ` + ruleTester.run( + 'Union and intersection types should not be defined with duplicated elements', + rule, + { + valid: [ + { + code: ` interface Person { age: number; name: string; @@ -38,50 +39,50 @@ describe('S4621', () => { type okUnion = number | string; type okUnionWithDifferentTypeParam = Loggable | Loggable; type okIntersection = Person & Loggable;`, - }, - ], - invalid: [ - { - code: `type nokUDuplicate = number | number | string;`, - errors: [ - { - message: `{"message":"Remove this duplicated type or replace with another one.","secondaryLocations":[{"message":"Original","column":21,"line":1,"endColumn":27,"endLine":1}]}`, - line: 1, - endLine: 1, - column: 31, - endColumn: 37, - suggestions: [ - { - desc: 'Remove duplicate types', - output: `type nokUDuplicate = number | string;`, - }, - ], - }, - ], - options: ['sonar-runtime'], - }, + }, + ], + invalid: [ + { + code: `type nokUDuplicate = number | number | string;`, + errors: [ + { + message: `{"message":"Remove this duplicated type or replace with another one.","secondaryLocations":[{"message":"Original","column":21,"line":1,"endColumn":27,"endLine":1}]}`, + line: 1, + endLine: 1, + column: 31, + endColumn: 37, + suggestions: [ + { + desc: 'Remove duplicate types', + output: `type nokUDuplicate = number | string;`, + }, + ], + }, + ], + options: ['sonar-runtime'], + }, - { - code: `type nokUDuplicate2 = number | number | number | string;`, - errors: [ - { - message: `{"message":"Remove this duplicated type or replace with another one.","secondaryLocations":[{"message":"Original","column":22,"line":1,"endColumn":28,"endLine":1},{"message":"Another duplicate","column":40,"line":1,"endColumn":46,"endLine":1}]}`, - line: 1, - endLine: 1, - column: 32, - endColumn: 38, - suggestions: [ - { - desc: 'Remove duplicate types', - output: `type nokUDuplicate2 = number | string;`, - }, - ], - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + { + code: `type nokUDuplicate2 = number | number | number | string;`, + errors: [ + { + message: `{"message":"Remove this duplicated type or replace with another one.","secondaryLocations":[{"message":"Original","column":22,"line":1,"endColumn":28,"endLine":1},{"message":"Another duplicate","column":40,"line":1,"endColumn":46,"endLine":1}]}`, + line: 1, + endLine: 1, + column: 32, + endColumn: 38, + suggestions: [ + { + desc: 'Remove duplicate types', + output: `type nokUDuplicate2 = number | string;`, + }, + ], + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` type nokUFunctionType = ((a: boolean) => boolean) | ((a: boolean) => boolean); type nokUTuple = [boolean, number] | [boolean, number]; type nokUArray = number [] | number []; @@ -94,141 +95,148 @@ describe('S4621', () => { type nokIArray = number [] & number []; type nokIStringLiteral = "ValueA" & "ValueA"; type nokIUnion = (number | string) & (number | string);`, - errors: 12, - }, - { - code: `type T = number | number`, - errors: [ - { - message: 'Remove this duplicated type or replace with another one.', - suggestions: [ - { - desc: 'Remove duplicate types', - output: `type T = number`, - }, - ], - }, - ], - }, - { - code: `type T = number & number`, - errors: [ - { - message: 'Remove this duplicated type or replace with another one.', - suggestions: [{ desc: 'Remove duplicate types', output: `type T = number` }], - }, - ], - }, - { - code: `type T = number | number | number`, - errors: [ - { - message: 'Remove this duplicated type or replace with another one.', - suggestions: [{ desc: 'Remove duplicate types', output: `type T = number` }], - }, - ], - }, - { - code: `type T = number | string | number`, - errors: [ - { - message: 'Remove this duplicated type or replace with another one.', - suggestions: [{ desc: 'Remove duplicate types', output: `type T = number | string` }], - }, - ], - }, - { - code: `type T = string | number | number`, - errors: [ - { - message: 'Remove this duplicated type or replace with another one.', - suggestions: [{ desc: 'Remove duplicate types', output: `type T = string | number` }], - }, - ], - }, - { - code: `type T = number | string | boolean | number`, - errors: [ - { - message: 'Remove this duplicated type or replace with another one.', - suggestions: [ - { desc: 'Remove duplicate types', output: `type T = number | string | boolean` }, - ], - }, - ], - }, - { - code: `type T = (number | string) & (number | string)`, - errors: [ - { - message: 'Remove this duplicated type or replace with another one.', - suggestions: [ - { desc: 'Remove duplicate types', output: `type T = (number | string)` }, - ], - }, - ], - }, - { - code: `type T = (number) | string | number`, - errors: [ - { - message: 'Remove this duplicated type or replace with another one.', - suggestions: [ - { desc: 'Remove duplicate types', output: `type T = (number) | string` }, - ], - }, - ], - }, - { - code: `type T = number | string | (number)`, - errors: [ - { - message: 'Remove this duplicated type or replace with another one.', - suggestions: [{ desc: 'Remove duplicate types', output: `type T = number | string` }], - }, - ], - }, - { - code: `type T = (number | string) & (number | string) & Foo`, - errors: [ - { - message: 'Remove this duplicated type or replace with another one.', - suggestions: [ - { desc: 'Remove duplicate types', output: `type T = (number | string) & Foo` }, - ], - }, - ], - }, - { - code: `type T = ((A) | B) & C & C`, - errors: [ - { - message: 'Remove this duplicated type or replace with another one.', - suggestions: [{ desc: 'Remove duplicate types', output: `type T = ((A) | B) & C` }], - }, - ], - }, - { - code: `type T = A & ((B)) & A`, - errors: [ - { - message: 'Remove this duplicated type or replace with another one.', - suggestions: [{ desc: 'Remove duplicate types', output: `type T = A & ((B))` }], - }, - ], - }, - { - code: `function foo(p: A | (B) | A) {}`, - errors: [ - { - message: 'Remove this duplicated type or replace with another one.', - suggestions: [ - { desc: 'Remove duplicate types', output: `function foo(p: A | (B)) {}` }, - ], - }, - ], - }, - ], - }, - ); + errors: 12, + }, + { + code: `type T = number | number`, + errors: [ + { + message: 'Remove this duplicated type or replace with another one.', + suggestions: [ + { + desc: 'Remove duplicate types', + output: `type T = number`, + }, + ], + }, + ], + }, + { + code: `type T = number & number`, + errors: [ + { + message: 'Remove this duplicated type or replace with another one.', + suggestions: [{ desc: 'Remove duplicate types', output: `type T = number` }], + }, + ], + }, + { + code: `type T = number | number | number`, + errors: [ + { + message: 'Remove this duplicated type or replace with another one.', + suggestions: [{ desc: 'Remove duplicate types', output: `type T = number` }], + }, + ], + }, + { + code: `type T = number | string | number`, + errors: [ + { + message: 'Remove this duplicated type or replace with another one.', + suggestions: [ + { desc: 'Remove duplicate types', output: `type T = number | string` }, + ], + }, + ], + }, + { + code: `type T = string | number | number`, + errors: [ + { + message: 'Remove this duplicated type or replace with another one.', + suggestions: [ + { desc: 'Remove duplicate types', output: `type T = string | number` }, + ], + }, + ], + }, + { + code: `type T = number | string | boolean | number`, + errors: [ + { + message: 'Remove this duplicated type or replace with another one.', + suggestions: [ + { desc: 'Remove duplicate types', output: `type T = number | string | boolean` }, + ], + }, + ], + }, + { + code: `type T = (number | string) & (number | string)`, + errors: [ + { + message: 'Remove this duplicated type or replace with another one.', + suggestions: [ + { desc: 'Remove duplicate types', output: `type T = (number | string)` }, + ], + }, + ], + }, + { + code: `type T = (number) | string | number`, + errors: [ + { + message: 'Remove this duplicated type or replace with another one.', + suggestions: [ + { desc: 'Remove duplicate types', output: `type T = (number) | string` }, + ], + }, + ], + }, + { + code: `type T = number | string | (number)`, + errors: [ + { + message: 'Remove this duplicated type or replace with another one.', + suggestions: [ + { desc: 'Remove duplicate types', output: `type T = number | string` }, + ], + }, + ], + }, + { + code: `type T = (number | string) & (number | string) & Foo`, + errors: [ + { + message: 'Remove this duplicated type or replace with another one.', + suggestions: [ + { desc: 'Remove duplicate types', output: `type T = (number | string) & Foo` }, + ], + }, + ], + }, + { + code: `type T = ((A) | B) & C & C`, + errors: [ + { + message: 'Remove this duplicated type or replace with another one.', + suggestions: [{ desc: 'Remove duplicate types', output: `type T = ((A) | B) & C` }], + }, + ], + }, + { + code: `type T = A & ((B)) & A`, + errors: [ + { + message: 'Remove this duplicated type or replace with another one.', + suggestions: [{ desc: 'Remove duplicate types', output: `type T = A & ((B))` }], + }, + ], + }, + { + code: `function foo(p: A | (B) | A) {}`, + errors: [ + { + message: 'Remove this duplicated type or replace with another one.', + suggestions: [ + { desc: 'Remove duplicate types', output: `function foo(p: A | (B)) {}` }, + ], + }, + ], + }, + ], + }, + ); + }); }); diff --git a/packages/jsts/src/rules/S4622/unit.test.ts b/packages/jsts/src/rules/S4622/unit.test.ts index 1d8f5b8256..4f5a00efca 100644 --- a/packages/jsts/src/rules/S4622/unit.test.ts +++ b/packages/jsts/src/rules/S4622/unit.test.ts @@ -16,62 +16,63 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4622', () => { - const ruleTester = new RuleTester(); + it('S4622', () => { + const ruleTester = new RuleTester(); - const DEFAULT_THRESHOLD = 3; - const CUSTOM_THRESHOLD = 4; + const DEFAULT_THRESHOLD = 3; + const CUSTOM_THRESHOLD = 4; - const createOptions = (threshold: number) => { - return [{ threshold }]; - }; + const createOptions = (threshold: number) => { + return [{ threshold }]; + }; - ruleTester.run('Union types should not have too many elements', rule, { - valid: [ - { - code: `let smallUnionType: number | boolean | string;`, - options: createOptions(DEFAULT_THRESHOLD), - }, - { - code: `let smallUnionType: number | boolean | string | any[];`, - options: createOptions(CUSTOM_THRESHOLD), - }, - { - code: `function smallUnionType(a: number | boolean) {}`, - options: createOptions(DEFAULT_THRESHOLD), - }, - { - code: `type T = A | B | C | D;`, - options: createOptions(DEFAULT_THRESHOLD), - }, - { - code: ` + ruleTester.run('Union types should not have too many elements', rule, { + valid: [ + { + code: `let smallUnionType: number | boolean | string;`, + options: createOptions(DEFAULT_THRESHOLD), + }, + { + code: `let smallUnionType: number | boolean | string | any[];`, + options: createOptions(CUSTOM_THRESHOLD), + }, + { + code: `function smallUnionType(a: number | boolean) {}`, + options: createOptions(DEFAULT_THRESHOLD), + }, + { + code: `type T = A | B | C | D;`, + options: createOptions(DEFAULT_THRESHOLD), + }, + { + code: ` type T = A | B | C | D; function okFn(a: T) {}`, - options: createOptions(DEFAULT_THRESHOLD), - }, - { - code: ` + options: createOptions(DEFAULT_THRESHOLD), + }, + { + code: ` type T = A | B | C | D; let okVarA : T;`, - options: createOptions(DEFAULT_THRESHOLD), - }, - { - code: ` + options: createOptions(DEFAULT_THRESHOLD), + }, + { + code: ` type T = A | B | C | D; let okFunctionType: (param: any) => T`, - options: createOptions(DEFAULT_THRESHOLD), - }, - { - code: ` + options: createOptions(DEFAULT_THRESHOLD), + }, + { + code: ` type T = A | B | C | D; let okTupleType: [string, T];`, - options: createOptions(DEFAULT_THRESHOLD), - }, - { - code: ` + options: createOptions(DEFAULT_THRESHOLD), + }, + { + code: ` interface Foo { a: string; b: number; @@ -82,83 +83,84 @@ describe('S4622', () => { }; type Bar = Pick; `, - options: createOptions(DEFAULT_THRESHOLD), - }, - ], - invalid: [ - { - code: `let nokVarA: A | B | C | D`, - options: createOptions(DEFAULT_THRESHOLD), - errors: [ - { - message: `Refactor this union type to have less than ${DEFAULT_THRESHOLD} elements.`, - line: 1, - endLine: 1, - column: 14, - endColumn: 27, - }, - ], - }, - { - code: `let nokVarA: A | B | C | D | E`, - options: createOptions(CUSTOM_THRESHOLD), - errors: [ - { - message: `Refactor this union type to have less than ${CUSTOM_THRESHOLD} elements.`, - line: 1, - endLine: 1, - column: 14, - endColumn: 31, - }, - ], - }, - { - code: `function nokFn(a: A | B | C | D) {}`, - options: createOptions(DEFAULT_THRESHOLD), - errors: [ - { - message: `Refactor this union type to have less than ${DEFAULT_THRESHOLD} elements.`, - }, - ], - }, - { - code: `let nokFunctionType: (param: any) => A | B | C | D`, - options: createOptions(DEFAULT_THRESHOLD), - errors: [ - { - message: `Refactor this union type to have less than ${DEFAULT_THRESHOLD} elements.`, - }, - ], - }, - { - code: `let nokTupleType : [string, A | B | C | D];`, - options: createOptions(DEFAULT_THRESHOLD), - errors: [ - { - message: `Refactor this union type to have less than ${DEFAULT_THRESHOLD} elements.`, - }, - ], - }, - { - code: `interface nokInterfaceDeclaration { + options: createOptions(DEFAULT_THRESHOLD), + }, + ], + invalid: [ + { + code: `let nokVarA: A | B | C | D`, + options: createOptions(DEFAULT_THRESHOLD), + errors: [ + { + message: `Refactor this union type to have less than ${DEFAULT_THRESHOLD} elements.`, + line: 1, + endLine: 1, + column: 14, + endColumn: 27, + }, + ], + }, + { + code: `let nokVarA: A | B | C | D | E`, + options: createOptions(CUSTOM_THRESHOLD), + errors: [ + { + message: `Refactor this union type to have less than ${CUSTOM_THRESHOLD} elements.`, + line: 1, + endLine: 1, + column: 14, + endColumn: 31, + }, + ], + }, + { + code: `function nokFn(a: A | B | C | D) {}`, + options: createOptions(DEFAULT_THRESHOLD), + errors: [ + { + message: `Refactor this union type to have less than ${DEFAULT_THRESHOLD} elements.`, + }, + ], + }, + { + code: `let nokFunctionType: (param: any) => A | B | C | D`, + options: createOptions(DEFAULT_THRESHOLD), + errors: [ + { + message: `Refactor this union type to have less than ${DEFAULT_THRESHOLD} elements.`, + }, + ], + }, + { + code: `let nokTupleType : [string, A | B | C | D];`, + options: createOptions(DEFAULT_THRESHOLD), + errors: [ + { + message: `Refactor this union type to have less than ${DEFAULT_THRESHOLD} elements.`, + }, + ], + }, + { + code: `interface nokInterfaceDeclaration { prop: A | B | C | D; }`, - options: createOptions(DEFAULT_THRESHOLD), - errors: [ - { - message: `Refactor this union type to have less than ${DEFAULT_THRESHOLD} elements.`, - }, - ], - }, - { - code: `type U = (A | B | C | D) & E;`, - options: createOptions(DEFAULT_THRESHOLD), - errors: [ - { - message: `Refactor this union type to have less than ${DEFAULT_THRESHOLD} elements.`, - }, - ], - }, - ], + options: createOptions(DEFAULT_THRESHOLD), + errors: [ + { + message: `Refactor this union type to have less than ${DEFAULT_THRESHOLD} elements.`, + }, + ], + }, + { + code: `type U = (A | B | C | D) & E;`, + options: createOptions(DEFAULT_THRESHOLD), + errors: [ + { + message: `Refactor this union type to have less than ${DEFAULT_THRESHOLD} elements.`, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4623/unit.test.ts b/packages/jsts/src/rules/S4623/unit.test.ts index e7d68f68e2..4345b27b54 100644 --- a/packages/jsts/src/rules/S4623/unit.test.ts +++ b/packages/jsts/src/rules/S4623/unit.test.ts @@ -16,149 +16,151 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4623', () => { - const ruleTester = new RuleTester(); - ruleTester.run(`"undefined" should not be passed as the value of optional parameters`, rule, { - valid: [ - { - code: ` + it('S4623', () => { + const ruleTester = new RuleTester(); + ruleTester.run(`"undefined" should not be passed as the value of optional parameters`, rule, { + valid: [ + { + code: ` function foo(p1: number | undefined, p2?: number, p3 = 42) {} foo(1, 2, 3); `, - }, - { - code: ` + }, + { + code: ` function foo(p1: number | undefined, p2?: number, p3 = 42) {} foo(1, 2); `, - }, - { - code: ` + }, + { + code: ` function foo(p1: number | undefined, p2?: number, p3 = 42) {} foo(1); `, - }, - { - code: ` + }, + { + code: ` function foo(p1: number | undefined, p2?: number, p3 = 42) {} foo(1, 2, [undefined].length); `, - }, - { - code: ` + }, + { + code: ` function foo(p1: number | undefined, p2?: number, p3 = 42) {} foo(undefined); // OK, it's not an optional parameter `, - }, - { - code: `unknownCalled(1, undefined);`, - }, - { - code: ` + }, + { + code: `unknownCalled(1, undefined);`, + }, + { + code: ` function bar() {} bar(undefined); // compile error but we should not explode `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function foo(p1: number | undefined, p2?: number, p3 = 42) {} foo(1, 2, undefined); `, - errors: [ - { - message: `Remove this redundant "undefined".`, - line: 3, - endLine: 3, - column: 17, - endColumn: 26, - suggestions: [ - { - desc: 'Remove this redundant argument', - output: ` + errors: [ + { + message: `Remove this redundant "undefined".`, + line: 3, + endLine: 3, + column: 17, + endColumn: 26, + suggestions: [ + { + desc: 'Remove this redundant argument', + output: ` function foo(p1: number | undefined, p2?: number, p3 = 42) {} foo(1, 2); `, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` function foo(p1: number | undefined, p2?: number, p3 = 42) {} foo(1, undefined, undefined); foo(1, undefined); `, - errors: 2, - }, - { - code: ` + errors: 2, + }, + { + code: ` let funcExprWithOneParameter = function(p = 42) {} funcExprWithOneParameter(undefined); funcExprWithOneParameter(1); `, - errors: 1, - }, - { - code: `function foo(p = 42) {}; foo(undefined);`, - errors: [ - { - messageId: 'removeUndefined', - suggestions: [ - { - desc: 'Remove this redundant argument', - output: 'function foo(p = 42) {}; foo();', - }, - ], - }, - ], - }, - { - code: `function foo(p = 42) {}; foo(undefined, );`, - errors: [ - { - messageId: 'removeUndefined', - suggestions: [ - { - desc: 'Remove this redundant argument', - output: 'function foo(p = 42) {}; foo();', - }, - ], - }, - ], - }, - { - code: `function foo(p, q = 42) {}; foo(1, undefined);`, - errors: [ - { - messageId: 'removeUndefined', - suggestions: [ - { - desc: 'Remove this redundant argument', - output: 'function foo(p, q = 42) {}; foo(1);', - }, - ], - }, - ], - }, - { - code: `function foo(p, q = 42) {}; foo(1, undefined, );`, - errors: [ - { - messageId: 'removeUndefined', - suggestions: [ - { - desc: 'Remove this redundant argument', - output: 'function foo(p, q = 42) {}; foo(1, );', - }, - ], - }, - ], - }, - ], + errors: 1, + }, + { + code: `function foo(p = 42) {}; foo(undefined);`, + errors: [ + { + messageId: 'removeUndefined', + suggestions: [ + { + desc: 'Remove this redundant argument', + output: 'function foo(p = 42) {}; foo();', + }, + ], + }, + ], + }, + { + code: `function foo(p = 42) {}; foo(undefined, );`, + errors: [ + { + messageId: 'removeUndefined', + suggestions: [ + { + desc: 'Remove this redundant argument', + output: 'function foo(p = 42) {}; foo();', + }, + ], + }, + ], + }, + { + code: `function foo(p, q = 42) {}; foo(1, undefined);`, + errors: [ + { + messageId: 'removeUndefined', + suggestions: [ + { + desc: 'Remove this redundant argument', + output: 'function foo(p, q = 42) {}; foo(1);', + }, + ], + }, + ], + }, + { + code: `function foo(p, q = 42) {}; foo(1, undefined, );`, + errors: [ + { + messageId: 'removeUndefined', + suggestions: [ + { + desc: 'Remove this redundant argument', + output: 'function foo(p, q = 42) {}; foo(1, );', + }, + ], + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4624/unit.test.ts b/packages/jsts/src/rules/S4624/unit.test.ts index 73db7fcced..51e24df039 100644 --- a/packages/jsts/src/rules/S4624/unit.test.ts +++ b/packages/jsts/src/rules/S4624/unit.test.ts @@ -16,136 +16,138 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4624', () => { - const ruleTester = new RuleTester(); + it('S4624', () => { + const ruleTester = new RuleTester(); - ruleTester.run('Template literals should not be nested', rule, { - valid: [ - { - code: 'let nestedMessage = `${count} ${color}`;', - }, - { - code: 'let message = `I have ${color ? nestedMessage : count} apples`;', - }, - { code: 'let message = `I have \n${color ? `${count} ${color}` : count} \napples`;' }, - ], - invalid: [ - { - code: 'let message = `I have ${color ? `${x ? `indeed 0` : count} ${color}` : count} apples`;', - errors: [ - { - messageId: 'nestedTemplateLiterals', - line: 1, - endLine: 1, - column: 33, - endColumn: 69, - }, - { - messageId: 'nestedTemplateLiterals', - line: 1, - endLine: 1, - column: 40, - endColumn: 50, - }, - ], - }, - { - code: 'let message = `I have ${color ? `${count} ${color}` : count} apples`;', - errors: [ - { - messageId: 'nestedTemplateLiterals', - line: 1, - endLine: 1, - column: 33, - endColumn: 52, - }, - ], - }, - { - code: 'let message = `I have ${color ? `${x ? `indeed ${0}` : count} ${color}` : count} apples`;', - errors: [ - { - messageId: 'nestedTemplateLiterals', - line: 1, - endLine: 1, - column: 33, - endColumn: 72, - }, - { - messageId: 'nestedTemplateLiterals', - line: 1, - endLine: 1, - column: 40, - endColumn: 53, - }, - ], - }, - { - code: - 'function tag(strings, ...keys) {console.log(strings[2]);}\n' + - 'let message1 = tag`I have ${color ? `${count} ${color}` : count} apples`;\n' + - 'let message2 = tag`I have ${color ? tag`${count} ${color}` : count} apples`;', - errors: [ - { - messageId: 'nestedTemplateLiterals', - line: 2, - endLine: 2, - column: 37, - endColumn: 56, - }, - { - messageId: 'nestedTemplateLiterals', - line: 3, - endLine: 3, - column: 40, - endColumn: 59, - }, - ], - }, - { - code: 'let message = `I have ${color ? `${count} ${color}` : `this is ${count}`} apples`;', - errors: [ - { - messageId: 'nestedTemplateLiterals', - line: 1, - endLine: 1, - column: 33, - endColumn: 52, - }, - { - messageId: 'nestedTemplateLiterals', - line: 1, - endLine: 1, - column: 55, - endColumn: 73, - }, - ], - }, - { - code: 'let message = `I have ${`${count} ${color}`} ${`this is ${count}`} apples`;', - errors: [ - { - messageId: 'nestedTemplateLiterals', - line: 1, - endLine: 1, - column: 25, - endColumn: 44, - }, - { - messageId: 'nestedTemplateLiterals', - line: 1, - endLine: 1, - column: 48, - endColumn: 66, - }, - ], - }, - { - code: 'let message = `I have \n${color ? `${count} ${color}` : count} apples`;', - errors: [{ messageId: 'nestedTemplateLiterals' }], - }, - ], + ruleTester.run('Template literals should not be nested', rule, { + valid: [ + { + code: 'let nestedMessage = `${count} ${color}`;', + }, + { + code: 'let message = `I have ${color ? nestedMessage : count} apples`;', + }, + { code: 'let message = `I have \n${color ? `${count} ${color}` : count} \napples`;' }, + ], + invalid: [ + { + code: 'let message = `I have ${color ? `${x ? `indeed 0` : count} ${color}` : count} apples`;', + errors: [ + { + messageId: 'nestedTemplateLiterals', + line: 1, + endLine: 1, + column: 33, + endColumn: 69, + }, + { + messageId: 'nestedTemplateLiterals', + line: 1, + endLine: 1, + column: 40, + endColumn: 50, + }, + ], + }, + { + code: 'let message = `I have ${color ? `${count} ${color}` : count} apples`;', + errors: [ + { + messageId: 'nestedTemplateLiterals', + line: 1, + endLine: 1, + column: 33, + endColumn: 52, + }, + ], + }, + { + code: 'let message = `I have ${color ? `${x ? `indeed ${0}` : count} ${color}` : count} apples`;', + errors: [ + { + messageId: 'nestedTemplateLiterals', + line: 1, + endLine: 1, + column: 33, + endColumn: 72, + }, + { + messageId: 'nestedTemplateLiterals', + line: 1, + endLine: 1, + column: 40, + endColumn: 53, + }, + ], + }, + { + code: + 'function tag(strings, ...keys) {console.log(strings[2]);}\n' + + 'let message1 = tag`I have ${color ? `${count} ${color}` : count} apples`;\n' + + 'let message2 = tag`I have ${color ? tag`${count} ${color}` : count} apples`;', + errors: [ + { + messageId: 'nestedTemplateLiterals', + line: 2, + endLine: 2, + column: 37, + endColumn: 56, + }, + { + messageId: 'nestedTemplateLiterals', + line: 3, + endLine: 3, + column: 40, + endColumn: 59, + }, + ], + }, + { + code: 'let message = `I have ${color ? `${count} ${color}` : `this is ${count}`} apples`;', + errors: [ + { + messageId: 'nestedTemplateLiterals', + line: 1, + endLine: 1, + column: 33, + endColumn: 52, + }, + { + messageId: 'nestedTemplateLiterals', + line: 1, + endLine: 1, + column: 55, + endColumn: 73, + }, + ], + }, + { + code: 'let message = `I have ${`${count} ${color}`} ${`this is ${count}`} apples`;', + errors: [ + { + messageId: 'nestedTemplateLiterals', + line: 1, + endLine: 1, + column: 25, + endColumn: 44, + }, + { + messageId: 'nestedTemplateLiterals', + line: 1, + endLine: 1, + column: 48, + endColumn: 66, + }, + ], + }, + { + code: 'let message = `I have \n${color ? `${count} ${color}` : count} apples`;', + errors: [{ messageId: 'nestedTemplateLiterals' }], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4634/unit.test.ts b/packages/jsts/src/rules/S4634/unit.test.ts index 5a0b54d181..5027a32570 100644 --- a/packages/jsts/src/rules/S4634/unit.test.ts +++ b/packages/jsts/src/rules/S4634/unit.test.ts @@ -16,108 +16,110 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4634', () => { - const ruleTester = new RuleTester(); + it('S4634', () => { + const ruleTester = new RuleTester(); - ruleTester.run('Shorthand promises should be used', rule, { - valid: [ - { - code: `let fulfilledPromise = new Promise(resolve => { resolve(calc(42)); console.log("foo"); });`, - }, - { - code: `let fulfilledPromise = Promise.resolve(42);`, - }, - { - code: `let fulfilledPromise = Promise.reject('fail');`, - }, - { - code: ` + ruleTester.run('Shorthand promises should be used', rule, { + valid: [ + { + code: `let fulfilledPromise = new Promise(resolve => { resolve(calc(42)); console.log("foo"); });`, + }, + { + code: `let fulfilledPromise = Promise.resolve(42);`, + }, + { + code: `let fulfilledPromise = Promise.reject('fail');`, + }, + { + code: ` function calc(x:number): number { return x * 2; } let somePromise = new Promise(() => { calc(42); }); // 0 parameters `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` let fulfilledPromise = new Promise(resolve => resolve(calc(42))); `, - errors: [ - { - message: `Replace this trivial promise with "Promise.resolve".`, - line: 2, - endLine: 2, - column: 34, - endColumn: 41, - suggestions: [ - { - desc: 'Replace with "Promise.resolve"', - output: ` + errors: [ + { + message: `Replace this trivial promise with "Promise.resolve".`, + line: 2, + endLine: 2, + column: 34, + endColumn: 41, + suggestions: [ + { + desc: 'Replace with "Promise.resolve"', + output: ` let fulfilledPromise = Promise.resolve(calc(42)); `, - }, - ], - }, - ], - }, - { - code: `let rejectedPromise = new Promise((resolve, reject) => reject(new Error('fail')));`, - errors: [ - { - message: `Replace this trivial promise with "Promise.reject".`, - suggestions: [ - { - desc: 'Replace with "Promise.reject"', - output: `let rejectedPromise = Promise.reject(new Error('fail'));`, - }, - ], - }, - ], - }, - { - code: `let rejectedPromise = new Promise((p1, p2) => p2(new Error('fail')));`, - errors: [ - { - message: `Replace this trivial promise with "Promise.reject".`, - suggestions: [ - { - desc: 'Replace with "Promise.reject"', - output: `let rejectedPromise = Promise.reject(new Error('fail'));`, - }, - ], - }, - ], - }, - { - code: `new Promise(resolve => resolve(calc(42)));`, - errors: [ - { - messageId: 'promiseAction', - suggestions: [ - { - desc: 'Replace with "Promise.resolve"', - output: 'Promise.resolve(calc(42));', - }, - ], - }, - ], - }, - { - code: `new Promise((resolve, reject) => reject(new Error('fail')));`, - errors: [ - { - messageId: 'promiseAction', - suggestions: [ - { - desc: 'Replace with "Promise.reject"', - output: `Promise.reject(new Error('fail'));`, - }, - ], - }, - ], - }, - ], + }, + ], + }, + ], + }, + { + code: `let rejectedPromise = new Promise((resolve, reject) => reject(new Error('fail')));`, + errors: [ + { + message: `Replace this trivial promise with "Promise.reject".`, + suggestions: [ + { + desc: 'Replace with "Promise.reject"', + output: `let rejectedPromise = Promise.reject(new Error('fail'));`, + }, + ], + }, + ], + }, + { + code: `let rejectedPromise = new Promise((p1, p2) => p2(new Error('fail')));`, + errors: [ + { + message: `Replace this trivial promise with "Promise.reject".`, + suggestions: [ + { + desc: 'Replace with "Promise.reject"', + output: `let rejectedPromise = Promise.reject(new Error('fail'));`, + }, + ], + }, + ], + }, + { + code: `new Promise(resolve => resolve(calc(42)));`, + errors: [ + { + messageId: 'promiseAction', + suggestions: [ + { + desc: 'Replace with "Promise.resolve"', + output: 'Promise.resolve(calc(42));', + }, + ], + }, + ], + }, + { + code: `new Promise((resolve, reject) => reject(new Error('fail')));`, + errors: [ + { + messageId: 'promiseAction', + suggestions: [ + { + desc: 'Replace with "Promise.reject"', + output: `Promise.reject(new Error('fail'));`, + }, + ], + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4721/unit.test.ts b/packages/jsts/src/rules/S4721/unit.test.ts index ce30ec7506..44b87bf46e 100644 --- a/packages/jsts/src/rules/S4721/unit.test.ts +++ b/packages/jsts/src/rules/S4721/unit.test.ts @@ -16,114 +16,116 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4721', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Executing OS commands is security-sensitive', rule, { - valid: [ - { - code: ` + it('S4721', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Executing OS commands is security-sensitive', rule, { + valid: [ + { + code: ` const cp = require('child_process'); cp.fork('child.js'); `, - }, - { - code: ` + }, + { + code: ` import { fork } from 'child_process'; fork('child.js');`, - }, - { - code: ` + }, + { + code: ` const cp = require('child_process'); cp.exec('echo child_process.exec hardcoded >> output.txt');`, - }, - { - code: ` + }, + { + code: ` const cp = require('child_process'); cp.spawn('echo child_process.exec hardcoded >> output.txt', { shell: true });`, - }, - { - code: ` + }, + { + code: ` const cp = require('child_process'); cp.spawn('echo child_process.spawn ' + userinput + ' >> output.txt', { shell: false });`, - }, - { - code: ` + }, + { + code: ` const cp = require('child_process'); cp.spawn('echo child_process.spawn ' + userinput + ' >> output.txt');`, - }, - { - code: ` + }, + { + code: ` const exec = require('child_process').fork; exec('echo child_process.exec ' + process.argv[2] + ' >> output.txt');`, - }, - { - code: ` + }, + { + code: ` import * as cp from 'child_process'; cp.spawn('echo child_process.exec ' + process.argv[2] + ' >> output.txt', { ...x });`, - }, - { - code: ` + }, + { + code: ` import { execSync } from 'child_process'; execSync(\`echo 'hello, world!'\`);`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const cp = require('child_process'); cp.exec('echo child_process.exec ' + userInput + ' >> output.txt'); `, - errors: [ - { - message: 'Make sure that executing this OS command is safe here.', - line: 3, - endLine: 3, - column: 9, - endColumn: 16, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Make sure that executing this OS command is safe here.', + line: 3, + endLine: 3, + column: 9, + endColumn: 16, + }, + ], + }, + { + code: ` import * as cp from 'child_process'; cp.exec('echo child_process.exec ' + process.argv[2] + ' >> output.txt');`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` import { exec } from 'child_process'; exec('echo child_process.exec ' + process.argv[2] + ' >> output.txt');`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` import * as cp from 'child_process'; cp.spawn('echo child_process.exec ' + process.argv[2] + ' >> output.txt', { shell: true });`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` import * as cp from 'child_process'; cp.exec('echo child_process.exec ' + process.argv[2] + ' >> output.txt', { env: "" });`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const exec = require('child_process').exec; exec('echo child_process.exec ' + process.argv[2] + ' >> output.txt');`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` var execSync = require('child_process').execSync function exec(command) { execSync(command, { stdio: [0, 1, 2] }) } `, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4782/unit.test.ts b/packages/jsts/src/rules/S4782/unit.test.ts index c04b1ba693..32b9351127 100644 --- a/packages/jsts/src/rules/S4782/unit.test.ts +++ b/packages/jsts/src/rules/S4782/unit.test.ts @@ -18,17 +18,18 @@ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import path from 'path'; import parser from '@typescript-eslint/parser'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4782', () => { - const ruleTester = new RuleTester(); - ruleTester.run( - `Optional property declarations should not use both '?' and 'undefined' syntax`, - rule, - { - valid: [ - { - code: ` + it('S4782', () => { + const ruleTester = new RuleTester(); + ruleTester.run( + `Optional property declarations should not use both '?' and 'undefined' syntax`, + rule, + { + valid: [ + { + code: ` interface Person { name: string; address: string | undefined; @@ -40,276 +41,277 @@ describe('S4782', () => { insurance: (undefined | string); color?: string; }`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` interface Person { name: string; address?: string | undefined; }`, - errors: [ - { - message: `{"message":"Consider removing 'undefined' type or '?' specifier, one of them is redundant.","secondaryLocations":[{"column":31,"line":4,"endColumn":40,"endLine":4}]}`, - line: 4, - endLine: 4, - column: 20, - endColumn: 21, - suggestions: [ - { - desc: 'Remove "?" operator', - output: ` + errors: [ + { + message: `{"message":"Consider removing 'undefined' type or '?' specifier, one of them is redundant.","secondaryLocations":[{"column":31,"line":4,"endColumn":40,"endLine":4}]}`, + line: 4, + endLine: 4, + column: 20, + endColumn: 21, + suggestions: [ + { + desc: 'Remove "?" operator', + output: ` interface Person { name: string; address: string | undefined; }`, - }, - { - desc: 'Remove "undefined" type annotation', - output: ` + }, + { + desc: 'Remove "undefined" type annotation', + output: ` interface Person { name: string; address?: string; }`, - }, - ], - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + }, + ], + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` class Person { address?: (string | (undefined | number)); name: string; }`, - errors: [ - { - message: JSON.stringify({ - message: - "Consider removing 'undefined' type or '?' specifier, one of them is redundant.", - secondaryLocations: [ + errors: [ + { + message: JSON.stringify({ + message: + "Consider removing 'undefined' type or '?' specifier, one of them is redundant.", + secondaryLocations: [ + { + column: 33, + line: 3, + endColumn: 42, + endLine: 3, + }, + ], + }), + line: 3, + endLine: 3, + suggestions: [ { - column: 33, - line: 3, - endColumn: 42, - endLine: 3, - }, - ], - }), - line: 3, - endLine: 3, - suggestions: [ - { - desc: 'Remove "?" operator', - output: ` + desc: 'Remove "?" operator', + output: ` class Person { address: (string | (undefined | number)); name: string; }`, - }, - { - desc: 'Remove "undefined" type annotation', - output: ` + }, + { + desc: 'Remove "undefined" type annotation', + output: ` class Person { address?: (string | number); name: string; }`, - }, - ], - }, - ], - options: ['sonar-runtime'], - }, - { - code: `interface T { p?: undefined | number; }`, - errors: [ - { - message: - "Consider removing 'undefined' type or '?' specifier, one of them is redundant.", - suggestions: [ - { - desc: 'Remove "?" operator', - output: 'interface T { p: undefined | number; }', - }, - { - desc: 'Remove "undefined" type annotation', - output: 'interface T { p?: number; }', - }, - ], - }, - ], - }, - { - code: `interface T { p?: number | undefined; }`, - errors: [ - { - message: - "Consider removing 'undefined' type or '?' specifier, one of them is redundant.", - suggestions: [ - { - desc: 'Remove "?" operator', - output: 'interface T { p: number | undefined; }', - }, - { - desc: 'Remove "undefined" type annotation', - output: 'interface T { p?: number; }', - }, - ], - }, - ], - }, - { - code: `interface T { p?: (undefined | number); }`, - errors: [ - { - message: - "Consider removing 'undefined' type or '?' specifier, one of them is redundant.", - suggestions: [ - { - desc: 'Remove "?" operator', - output: 'interface T { p: (undefined | number); }', - }, - { - desc: 'Remove "undefined" type annotation', - output: 'interface T { p?: number; }', - }, - ], - }, - ], - }, - { - code: `interface T { p?: undefined | number | string; }`, - errors: [ - { - message: - "Consider removing 'undefined' type or '?' specifier, one of them is redundant.", - suggestions: [ - { - desc: 'Remove "?" operator', - output: 'interface T { p: undefined | number | string; }', - }, - { - desc: 'Remove "undefined" type annotation', - output: 'interface T { p?: number | string; }', - }, - ], - }, - ], - }, - { - code: `interface T { p?: number | undefined | string; }`, - errors: [ - { - message: - "Consider removing 'undefined' type or '?' specifier, one of them is redundant.", - suggestions: [ - { - desc: 'Remove "?" operator', - output: 'interface T { p: number | undefined | string; }', - }, - { - desc: 'Remove "undefined" type annotation', - output: 'interface T { p?: number | string; }', - }, - ], - }, - ], - }, - { - code: `interface T { p?: number | string | undefined; }`, - errors: [ - { - message: - "Consider removing 'undefined' type or '?' specifier, one of them is redundant.", - suggestions: [ - { - desc: 'Remove "?" operator', - output: 'interface T { p: number | string | undefined; }', - }, - { - desc: 'Remove "undefined" type annotation', - output: 'interface T { p?: number | string; }', - }, - ], - }, - ], - }, - { - code: `interface T { p?: number | (string | undefined); }`, - errors: [ - { - message: - "Consider removing 'undefined' type or '?' specifier, one of them is redundant.", - suggestions: [ - { - desc: 'Remove "?" operator', - output: 'interface T { p: number | (string | undefined); }', - }, - { - desc: 'Remove "undefined" type annotation', - output: 'interface T { p?: number | string; }', - }, - ], - }, - ], - }, - { - code: `interface T { p?: undefined; }`, - errors: [ - { - message: - "Consider removing 'undefined' type or '?' specifier, one of them is redundant.", - suggestions: [ - { - desc: 'Remove "?" operator', - output: 'interface T { p: undefined; }', - }, - ], - }, - ], - }, + }, + ], + }, + ], + options: ['sonar-runtime'], + }, + { + code: `interface T { p?: undefined | number; }`, + errors: [ + { + message: + "Consider removing 'undefined' type or '?' specifier, one of them is redundant.", + suggestions: [ + { + desc: 'Remove "?" operator', + output: 'interface T { p: undefined | number; }', + }, + { + desc: 'Remove "undefined" type annotation', + output: 'interface T { p?: number; }', + }, + ], + }, + ], + }, + { + code: `interface T { p?: number | undefined; }`, + errors: [ + { + message: + "Consider removing 'undefined' type or '?' specifier, one of them is redundant.", + suggestions: [ + { + desc: 'Remove "?" operator', + output: 'interface T { p: number | undefined; }', + }, + { + desc: 'Remove "undefined" type annotation', + output: 'interface T { p?: number; }', + }, + ], + }, + ], + }, + { + code: `interface T { p?: (undefined | number); }`, + errors: [ + { + message: + "Consider removing 'undefined' type or '?' specifier, one of them is redundant.", + suggestions: [ + { + desc: 'Remove "?" operator', + output: 'interface T { p: (undefined | number); }', + }, + { + desc: 'Remove "undefined" type annotation', + output: 'interface T { p?: number; }', + }, + ], + }, + ], + }, + { + code: `interface T { p?: undefined | number | string; }`, + errors: [ + { + message: + "Consider removing 'undefined' type or '?' specifier, one of them is redundant.", + suggestions: [ + { + desc: 'Remove "?" operator', + output: 'interface T { p: undefined | number | string; }', + }, + { + desc: 'Remove "undefined" type annotation', + output: 'interface T { p?: number | string; }', + }, + ], + }, + ], + }, + { + code: `interface T { p?: number | undefined | string; }`, + errors: [ + { + message: + "Consider removing 'undefined' type or '?' specifier, one of them is redundant.", + suggestions: [ + { + desc: 'Remove "?" operator', + output: 'interface T { p: number | undefined | string; }', + }, + { + desc: 'Remove "undefined" type annotation', + output: 'interface T { p?: number | string; }', + }, + ], + }, + ], + }, + { + code: `interface T { p?: number | string | undefined; }`, + errors: [ + { + message: + "Consider removing 'undefined' type or '?' specifier, one of them is redundant.", + suggestions: [ + { + desc: 'Remove "?" operator', + output: 'interface T { p: number | string | undefined; }', + }, + { + desc: 'Remove "undefined" type annotation', + output: 'interface T { p?: number | string; }', + }, + ], + }, + ], + }, + { + code: `interface T { p?: number | (string | undefined); }`, + errors: [ + { + message: + "Consider removing 'undefined' type or '?' specifier, one of them is redundant.", + suggestions: [ + { + desc: 'Remove "?" operator', + output: 'interface T { p: number | (string | undefined); }', + }, + { + desc: 'Remove "undefined" type annotation', + output: 'interface T { p?: number | string; }', + }, + ], + }, + ], + }, + { + code: `interface T { p?: undefined; }`, + errors: [ + { + message: + "Consider removing 'undefined' type or '?' specifier, one of them is redundant.", + suggestions: [ + { + desc: 'Remove "?" operator', + output: 'interface T { p: undefined; }', + }, + ], + }, + ], + }, + { + code: `interface T { p?: (undefined) | number; }`, + errors: [ + { + message: + "Consider removing 'undefined' type or '?' specifier, one of them is redundant.", + suggestions: [ + { + desc: 'Remove "?" operator', + output: 'interface T { p: (undefined) | number; }', + }, + { + desc: 'Remove "undefined" type annotation', + output: 'interface T { p?: number; }', + }, + ], + }, + ], + }, + ], + }, + ); + + const noopRuleTester = new RuleTester({ + parser, + ecmaVersion: 2018, + sourceType: 'module', + parserOptions: { + project: `tsconfig.json`, + tsconfigRootDir: path.join(import.meta.dirname, 'fixtures'), + }, + }); + + noopRuleTester.run('S4782 becomes noop when exactOptionalPropertyTypes is enabled', rule, { + valid: [ { - code: `interface T { p?: (undefined) | number; }`, - errors: [ - { - message: - "Consider removing 'undefined' type or '?' specifier, one of them is redundant.", - suggestions: [ - { - desc: 'Remove "?" operator', - output: 'interface T { p: (undefined) | number; }', - }, - { - desc: 'Remove "undefined" type annotation', - output: 'interface T { p?: number; }', - }, - ], - }, - ], + code: 'interface T { p?: string | undefined; }', + filename: path.join(import.meta.dirname, 'fixtures', 'index.ts'), }, ], - }, - ); - - const noopRuleTester = new RuleTester({ - parser, - ecmaVersion: 2018, - sourceType: 'module', - parserOptions: { - project: `tsconfig.json`, - tsconfigRootDir: path.join(import.meta.dirname, 'fixtures'), - }, - }); - - noopRuleTester.run('S4782 becomes noop when exactOptionalPropertyTypes is enabled', rule, { - valid: [ - { - code: 'interface T { p?: string | undefined; }', - filename: path.join(import.meta.dirname, 'fixtures', 'index.ts'), - }, - ], - invalid: [], + invalid: [], + }); }); }); diff --git a/packages/jsts/src/rules/S4784/unit.test.ts b/packages/jsts/src/rules/S4784/unit.test.ts index 2786910f60..5d1cbcd100 100644 --- a/packages/jsts/src/rules/S4784/unit.test.ts +++ b/packages/jsts/src/rules/S4784/unit.test.ts @@ -16,92 +16,94 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4784', () => { - const ruleTester = new RuleTester(); + it('S4784', () => { + const ruleTester = new RuleTester(); - const message = 'Make sure that using a regular expression is safe here.'; + const message = 'Make sure that using a regular expression is safe here.'; - ruleTester.run('Using regular expressions is security-sensitive', rule, { - valid: [ - { - // not enough of special symbols - code: `str.match("(a+)b");`, - }, - { - // not enough of special symbols - code: `str.match(/(a+)b/);`, - }, - { - // different method - code: `str.foo("(a+)b+");`, - }, - { - // argument is not hardcoded literal - code: `str.match(foo("(a+)b+"));`, - }, - { - // FN - code: `const x = "(a+)b+"; str.match(x);`, - }, - { - // not enough length - code: `str.match("++");`, - }, - { - // missing argument - code: `str.match();`, - }, - ], - invalid: [ - { - code: `str.match("(a+)+b");`, - errors: [ - { - message, - line: 1, - endLine: 1, - column: 11, - endColumn: 19, - }, - ], - }, + ruleTester.run('Using regular expressions is security-sensitive', rule, { + valid: [ + { + // not enough of special symbols + code: `str.match("(a+)b");`, + }, + { + // not enough of special symbols + code: `str.match(/(a+)b/);`, + }, + { + // different method + code: `str.foo("(a+)b+");`, + }, + { + // argument is not hardcoded literal + code: `str.match(foo("(a+)b+"));`, + }, + { + // FN + code: `const x = "(a+)b+"; str.match(x);`, + }, + { + // not enough length + code: `str.match("++");`, + }, + { + // missing argument + code: `str.match();`, + }, + ], + invalid: [ + { + code: `str.match("(a+)+b");`, + errors: [ + { + message, + line: 1, + endLine: 1, + column: 11, + endColumn: 19, + }, + ], + }, - { - code: `str.match("+++");`, - errors: [{ message }], - }, - { - code: `str.match("***");`, - errors: [{ message }], - }, - { - code: `str.match("{{{");`, - errors: [{ message }], - }, - { - code: `str.match(/(a+)+b/);`, - errors: [{ message }], - }, + { + code: `str.match("+++");`, + errors: [{ message }], + }, + { + code: `str.match("***");`, + errors: [{ message }], + }, + { + code: `str.match("{{{");`, + errors: [{ message }], + }, + { + code: `str.match(/(a+)+b/);`, + errors: [{ message }], + }, - { - code: `str.split("(a+)+b");`, - errors: [{ message }], - }, - { - code: `str.search("(a+)+b");`, - errors: [{ message }], - }, - { - code: `new RegExp("(a+)+b");`, - errors: [{ message }], - }, + { + code: `str.split("(a+)+b");`, + errors: [{ message }], + }, + { + code: `str.search("(a+)+b");`, + errors: [{ message }], + }, + { + code: `new RegExp("(a+)+b");`, + errors: [{ message }], + }, - { - code: `/(a+)+b/;`, - errors: [{ message }], - }, - ], + { + code: `/(a+)+b/;`, + errors: [{ message }], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4787/unit.test.ts b/packages/jsts/src/rules/S4787/unit.test.ts index 1a759965d8..a90fa321d3 100644 --- a/packages/jsts/src/rules/S4787/unit.test.ts +++ b/packages/jsts/src/rules/S4787/unit.test.ts @@ -16,103 +16,105 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4787', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Encrypting data is security-sensitive: client side', rule, { - valid: [ - { - // no call - code: `crypto.subtle.encrypt`, - }, - { - // not "encrypt" or "decrypt" - code: `crypto.subtle.digest()`, - }, - { - // no "crypto.subtle" - code: `foo.encrypt()`, - }, - ], - invalid: [ - { - code: `crypto.subtle.encrypt(algorithm, key, plainData);`, - errors: [ - { - message: 'Make sure that encrypting data is safe here.', - line: 1, - endLine: 1, - column: 1, - endColumn: 22, - }, - ], - }, - { - code: `let subtle = crypto.subtle; subtle.encrypt();`, - errors: 1, - }, - { - code: `let encrypt = crypto.subtle.encrypt; encrypt();`, - errors: 1, - }, - { - code: `let subtle = window.crypto.subtle; subtle.decrypt();`, - errors: 1, - }, - ], - }); + it('S4787', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Encrypting data is security-sensitive: client side', rule, { + valid: [ + { + // no call + code: `crypto.subtle.encrypt`, + }, + { + // not "encrypt" or "decrypt" + code: `crypto.subtle.digest()`, + }, + { + // no "crypto.subtle" + code: `foo.encrypt()`, + }, + ], + invalid: [ + { + code: `crypto.subtle.encrypt(algorithm, key, plainData);`, + errors: [ + { + message: 'Make sure that encrypting data is safe here.', + line: 1, + endLine: 1, + column: 1, + endColumn: 22, + }, + ], + }, + { + code: `let subtle = crypto.subtle; subtle.encrypt();`, + errors: 1, + }, + { + code: `let encrypt = crypto.subtle.encrypt; encrypt();`, + errors: 1, + }, + { + code: `let subtle = window.crypto.subtle; subtle.decrypt();`, + errors: 1, + }, + ], + }); - ruleTester.run('Encrypting data is security-sensitive: server side', rule, { - valid: [ - { - code: `const crypto = require('foo'); crypto.createCipher();`, - }, - { - code: `const crypto = require('crypto'); crypto.scryptSync();`, - }, - { - code: `import * as bar from 'crypto'; foo.createCipher();`, - }, - { - code: `import * as crypto from 'foo'; crypto.createCipher();`, - }, - { - code: `import * as crypto from 'crypto'; crypto.scryptSync();`, - }, - { - code: `const createCipher = require('foo').createCipher; createCipher();`, - }, - ], - invalid: [ - { - code: `const crypto = require('crypto'); crypto.createCipher();`, - errors: [ - { - message: 'Make sure that encrypting data is safe here.', - line: 1, - endLine: 1, - column: 35, - endColumn: 54, - }, - ], - }, - { - code: `const createCipher = require('crypto').createCipher; createCipher();`, - errors: 1, - }, - { - code: `import * as foo from 'crypto'; foo.createCipher();`, - errors: 1, - }, - { - code: `import { createCipher } from 'crypto'; createCipher();`, - errors: 1, - }, - { - code: `import { publicEncrypt } from 'crypto'; publicEncrypt();`, - errors: 1, - }, - ], + ruleTester.run('Encrypting data is security-sensitive: server side', rule, { + valid: [ + { + code: `const crypto = require('foo'); crypto.createCipher();`, + }, + { + code: `const crypto = require('crypto'); crypto.scryptSync();`, + }, + { + code: `import * as bar from 'crypto'; foo.createCipher();`, + }, + { + code: `import * as crypto from 'foo'; crypto.createCipher();`, + }, + { + code: `import * as crypto from 'crypto'; crypto.scryptSync();`, + }, + { + code: `const createCipher = require('foo').createCipher; createCipher();`, + }, + ], + invalid: [ + { + code: `const crypto = require('crypto'); crypto.createCipher();`, + errors: [ + { + message: 'Make sure that encrypting data is safe here.', + line: 1, + endLine: 1, + column: 35, + endColumn: 54, + }, + ], + }, + { + code: `const createCipher = require('crypto').createCipher; createCipher();`, + errors: 1, + }, + { + code: `import * as foo from 'crypto'; foo.createCipher();`, + errors: 1, + }, + { + code: `import { createCipher } from 'crypto'; createCipher();`, + errors: 1, + }, + { + code: `import { publicEncrypt } from 'crypto'; publicEncrypt();`, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4798/unit.test.ts b/packages/jsts/src/rules/S4798/unit.test.ts index 77f41e207e..a8086d04ec 100644 --- a/packages/jsts/src/rules/S4798/unit.test.ts +++ b/packages/jsts/src/rules/S4798/unit.test.ts @@ -16,80 +16,82 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4798', () => { - const ruleTester = new RuleTester(); + it('S4798', () => { + const ruleTester = new RuleTester(); - ruleTester.run('Optional boolean parameters should have default value', rule, { - valid: [ - { - code: `function f(b: boolean = false) {}`, - }, - { - code: `function f(b: boolean | undefined = true) {}`, - }, - { - code: `function f(b: boolean | string) {}`, - }, - { - code: `function f(b: boolean & string) {}`, - }, - { - code: `function f(b?: string) {}`, - }, - { - code: `abstract class A{ + ruleTester.run('Optional boolean parameters should have default value', rule, { + valid: [ + { + code: `function f(b: boolean = false) {}`, + }, + { + code: `function f(b: boolean | undefined = true) {}`, + }, + { + code: `function f(b: boolean | string) {}`, + }, + { + code: `function f(b: boolean & string) {}`, + }, + { + code: `function f(b?: string) {}`, + }, + { + code: `abstract class A{ abstract foo(p?: boolean): number; }`, - }, - { - code: `function foo(b?: boolean);`, - }, - { - code: `interface i { + }, + { + code: `function foo(b?: boolean);`, + }, + { + code: `interface i { m(b?: boolean): void; new (b?: boolean): void; // Construct signatures can not contain initializer (b?: boolean): void; // Call signatures can not contain initializer }`, - }, - { - code: `type Foo = (p?: boolean) => void; //A parameter initializer is only allowed in a function or constructor implementation`, - }, - ], - invalid: [ - { - code: `function f(b?: boolean) {}`, - errors: [ - { - message: `Provide a default value for 'b' so that the logic of the function is more evident when this parameter is missing. Consider defining another function if providing default value is not possible.`, - line: 1, - endLine: 1, - column: 12, - endColumn: 23, - }, - ], - }, - { - code: `function f(b: boolean | undefined) {}`, - errors: 1, - }, - { - code: `function f(b: undefined | boolean) {}`, - errors: 1, - }, - { - code: `let f = (b?: boolean) => b;`, - errors: 1, - }, - { - code: ` + }, + { + code: `type Foo = (p?: boolean) => void; //A parameter initializer is only allowed in a function or constructor implementation`, + }, + ], + invalid: [ + { + code: `function f(b?: boolean) {}`, + errors: [ + { + message: `Provide a default value for 'b' so that the logic of the function is more evident when this parameter is missing. Consider defining another function if providing default value is not possible.`, + line: 1, + endLine: 1, + column: 12, + endColumn: 23, + }, + ], + }, + { + code: `function f(b: boolean | undefined) {}`, + errors: 1, + }, + { + code: `function f(b: undefined | boolean) {}`, + errors: 1, + }, + { + code: `let f = (b?: boolean) => b;`, + errors: 1, + }, + { + code: ` class c { m(b?: boolean): void {} } `, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4817/unit.test.ts b/packages/jsts/src/rules/S4817/unit.test.ts index faeb2887d2..0c1b8233b2 100644 --- a/packages/jsts/src/rules/S4817/unit.test.ts +++ b/packages/jsts/src/rules/S4817/unit.test.ts @@ -16,125 +16,127 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4817', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Executing XPath expressions is security-sensitive', rule, { - valid: [ - { - code: ` + it('S4817', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Executing XPath expressions is security-sensitive', rule, { + valid: [ + { + code: ` const xpath = require('xpath'); xpath.parse(expr);`, - }, - { - code: ` + }, + { + code: ` const xpath = require('x'); xpath.select(expr);`, - }, - { - code: ` + }, + { + code: ` const select = require('xpath').parse; select(expr);`, - }, - { - code: ` + }, + { + code: ` import foo from 'xpath'; foo.parse(expr);`, - }, - { - code: `a.selectNodesFoo(expr)`, - }, - { - code: `a.selectNodes(expr1, expr2)`, - }, - { - code: `document.evaluateFoo(userInput, xmlDoc, null, XPathResult.ANY_TYPE, null);`, - }, - { - code: `foo.evaluate(userInput, xmlDoc, null, foo);`, - }, - { - code: ` + }, + { + code: `a.selectNodesFoo(expr)`, + }, + { + code: `a.selectNodes(expr1, expr2)`, + }, + { + code: `document.evaluateFoo(userInput, xmlDoc, null, XPathResult.ANY_TYPE, null);`, + }, + { + code: `foo.evaluate(userInput, xmlDoc, null, foo);`, + }, + { + code: ` const xpath = require('xpath'); xpath.select('foo/bar'); xpath.select1('foo/bar'); xpath.evaluate('foo/bar'); a.selectNodes('foo/bar'); a.SelectSingleNode('foo/bar')`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const xpath = require('xpath'); xpath.select(expr);`, - errors: [ - { - message: 'Make sure that executing this XPATH expression is safe.', - line: 3, - endLine: 3, - column: 9, - endColumn: 21, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Make sure that executing this XPATH expression is safe.', + line: 3, + endLine: 3, + column: 9, + endColumn: 21, + }, + ], + }, + { + code: ` const xpath = require('xpath'); xpath.select1(expr);`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const select = require('xpath').select; select(expr);`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` import { select1 } from 'xpath'; select1(expr);`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` import { evaluate } from 'xpath'; evaluate(expr);`, - errors: 1, - }, - { - code: `a.selectNodes(expr)`, - errors: [ - { - message: 'Make sure that executing this XPATH expression is safe.', - line: 1, - endLine: 1, - column: 1, - endColumn: 14, - }, - ], - }, - { - code: `a.b.selectNodes(expr)`, - errors: 1, - }, - { - code: `a.b().SelectSingleNode(expr)`, - errors: 1, - }, - { - code: `document.evaluate(userInput, xmlDoc, null, XPathResult.ANY_TYPE, null);`, - errors: 1, - }, - { - code: `foo.bar.evaluate(userInput, xmlDoc, null, XPathResult.STRING_TYPE);`, - errors: 1, - }, - { - code: `foo(document.evaluate)`, - errors: 1, - }, - ], + errors: 1, + }, + { + code: `a.selectNodes(expr)`, + errors: [ + { + message: 'Make sure that executing this XPATH expression is safe.', + line: 1, + endLine: 1, + column: 1, + endColumn: 14, + }, + ], + }, + { + code: `a.b.selectNodes(expr)`, + errors: 1, + }, + { + code: `a.b().SelectSingleNode(expr)`, + errors: 1, + }, + { + code: `document.evaluate(userInput, xmlDoc, null, XPathResult.ANY_TYPE, null);`, + errors: 1, + }, + { + code: `foo.bar.evaluate(userInput, xmlDoc, null, XPathResult.STRING_TYPE);`, + errors: 1, + }, + { + code: `foo(document.evaluate)`, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4818/unit.test.ts b/packages/jsts/src/rules/S4818/unit.test.ts index 833a9176e9..691d4b5ef3 100644 --- a/packages/jsts/src/rules/S4818/unit.test.ts +++ b/packages/jsts/src/rules/S4818/unit.test.ts @@ -16,53 +16,55 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4818', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Handling files is security-sensitive', rule, { - valid: [ - { - code: ` + it('S4818', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Handling files is security-sensitive', rule, { + valid: [ + { + code: ` const net = require('net'); net.createServer(); `, - }, - { - code: ` + }, + { + code: ` new net.Socket(); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const net = require('net'); new net.Socket(); `, - errors: [ - { - message: 'Make sure that sockets are used safely here.', - line: 3, - endLine: 3, - column: 13, - endColumn: 23, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Make sure that sockets are used safely here.', + line: 3, + endLine: 3, + column: 13, + endColumn: 23, + }, + ], + }, + { + code: ` const net = require('net'); net.createConnection({ port: port }, () => {});`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` import { connect } from 'net' connect({ port: port }, () => {});; `, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4822/unit.test.ts b/packages/jsts/src/rules/S4822/unit.test.ts index 9c2d6a39a0..631eed1058 100644 --- a/packages/jsts/src/rules/S4822/unit.test.ts +++ b/packages/jsts/src/rules/S4822/unit.test.ts @@ -16,14 +16,15 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4822', () => { - const ruleTester = new RuleTester(); - ruleTester.run(`Promise rejections should not be caught by 'try' block`, rule, { - valid: [ - { - code: ` + it('S4822', () => { + const ruleTester = new RuleTester(); + ruleTester.run(`Promise rejections should not be caught by 'try' block`, rule, { + valid: [ + { + code: ` function returningPromise() { return Promise.reject(); } async function okWithAwait() { try { @@ -33,9 +34,9 @@ describe('S4822', () => { } } `, - }, - { - code: ` + }, + { + code: ` function returningPromise() { return Promise.reject(); } function okWithAnotherCall() { try { @@ -46,9 +47,9 @@ describe('S4822', () => { } } `, - }, - { - code: ` + }, + { + code: ` function returningPromise() { return Promise.reject(); } function okWithoutCatch() { try { @@ -58,9 +59,9 @@ describe('S4822', () => { } } `, - }, - { - code: ` + }, + { + code: ` function returningPromise() { return Promise.reject(); } function okWithNestedFunc() { try { @@ -70,9 +71,9 @@ describe('S4822', () => { } } `, - }, - { - code: ` + }, + { + code: ` function returningPromise() { return Promise.reject(); } async function okWithAwaitAndPromise() { try { @@ -83,9 +84,9 @@ describe('S4822', () => { } } `, - }, - { - code: ` + }, + { + code: ` function returningPromise() { return Promise.reject(); } async function * okWithYield() { try { @@ -95,11 +96,11 @@ describe('S4822', () => { } } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function returningPromise() { return Promise.reject(); } function singlePromise() { try { @@ -109,19 +110,19 @@ describe('S4822', () => { } } `, - errors: [ - { - message: `{"message":"Consider using 'await' for the promise inside this 'try' or replace it with 'Promise.prototype.catch(...)' usage.","secondaryLocations":[{"message":"Promise","column":10,"line":5,"endColumn":28,"endLine":5}]}`, - line: 4, - endLine: 4, - column: 9, - endColumn: 12, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: `{"message":"Consider using 'await' for the promise inside this 'try' or replace it with 'Promise.prototype.catch(...)' usage.","secondaryLocations":[{"message":"Promise","column":10,"line":5,"endColumn":28,"endLine":5}]}`, + line: 4, + endLine: 4, + column: 9, + endColumn: 12, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` function returningPromise() { return Promise.reject(); } function uselessTry() { try { @@ -131,19 +132,19 @@ describe('S4822', () => { } } `, - errors: [ - { - message: `{"message":"Consider removing this 'try' statement as promise rejection is already captured by '.catch()' method.","secondaryLocations":[{"message":"Caught promise","column":10,"line":5,"endColumn":28,"endLine":5}]}`, - line: 4, - endLine: 4, - column: 9, - endColumn: 12, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: `{"message":"Consider removing this 'try' statement as promise rejection is already captured by '.catch()' method.","secondaryLocations":[{"message":"Caught promise","column":10,"line":5,"endColumn":28,"endLine":5}]}`, + line: 4, + endLine: 4, + column: 9, + endColumn: 12, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` function returningPromise() { return Promise.reject(); } function conditionalPromise(cond: boolean) { try { @@ -158,10 +159,10 @@ describe('S4822', () => { } } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` function returningPromise() { return Promise.reject(); } async function severalTry() { try { @@ -177,10 +178,10 @@ describe('S4822', () => { } } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` function returningPromise() { return Promise.reject(); } function newPromise() { try { @@ -190,10 +191,10 @@ describe('S4822', () => { } } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` function returningPromiseAndThrowing(cond: boolean) { if (cond) { return new Promise((res, rej) => {}); @@ -211,10 +212,10 @@ describe('S4822', () => { } } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` function returningPromise() { return Promise.reject(); } function uselessTryThenCatch() { try { @@ -224,10 +225,10 @@ describe('S4822', () => { } } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` function returningPromise() { return Promise.reject(); } function onlyOnePromiseWhenChainedPromise() { try { @@ -237,8 +238,9 @@ describe('S4822', () => { } } `, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4823/unit.test.ts b/packages/jsts/src/rules/S4823/unit.test.ts index 6426c2e82e..05a385e26e 100644 --- a/packages/jsts/src/rules/S4823/unit.test.ts +++ b/packages/jsts/src/rules/S4823/unit.test.ts @@ -16,42 +16,44 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4823', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Using command line arguments is security-sensitive', rule, { - valid: [ - { - code: `foo.bar`, - }, - { - code: `process.argvFoo`, - }, - { - code: `processFoo.argv`, - }, - { - code: `'process.argv'`, - }, - ], - invalid: [ - { - code: `let x = process.argv;`, - errors: [ - { - message: 'Make sure that command line arguments are used safely here.', - line: 1, - endLine: 1, - column: 9, - endColumn: 21, - }, - ], - }, - { - code: `\`argument 0: \${process.argv[0]}\``, - errors: 1, - }, - ], + it('S4823', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Using command line arguments is security-sensitive', rule, { + valid: [ + { + code: `foo.bar`, + }, + { + code: `process.argvFoo`, + }, + { + code: `processFoo.argv`, + }, + { + code: `'process.argv'`, + }, + ], + invalid: [ + { + code: `let x = process.argv;`, + errors: [ + { + message: 'Make sure that command line arguments are used safely here.', + line: 1, + endLine: 1, + column: 9, + endColumn: 21, + }, + ], + }, + { + code: `\`argument 0: \${process.argv[0]}\``, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4829/unit.test.ts b/packages/jsts/src/rules/S4829/unit.test.ts index edce93e140..b0af5e56f3 100644 --- a/packages/jsts/src/rules/S4829/unit.test.ts +++ b/packages/jsts/src/rules/S4829/unit.test.ts @@ -16,42 +16,44 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4829', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Reading the Standard Input is security-sensitive', rule, { - valid: [ - { - code: `foo.bar`, - }, - { - code: `process.stdout`, - }, - { - code: `processFoo.stdin`, - }, - { - code: `'process.stdin'`, - }, - ], - invalid: [ - { - code: `let x = process.stdin;`, - errors: [ - { - message: 'Make sure that reading the standard input is safe here.', - line: 1, - endLine: 1, - column: 9, - endColumn: 22, - }, - ], - }, - { - code: `process.stdin.on('readable', () => {});`, - errors: 1, - }, - ], + it('S4829', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Reading the Standard Input is security-sensitive', rule, { + valid: [ + { + code: `foo.bar`, + }, + { + code: `process.stdout`, + }, + { + code: `processFoo.stdin`, + }, + { + code: `'process.stdin'`, + }, + ], + invalid: [ + { + code: `let x = process.stdin;`, + errors: [ + { + message: 'Make sure that reading the standard input is safe here.', + line: 1, + endLine: 1, + column: 9, + endColumn: 22, + }, + ], + }, + { + code: `process.stdin.on('readable', () => {});`, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S4830/unit.test.ts b/packages/jsts/src/rules/S4830/unit.test.ts index df36331356..d965c7da88 100644 --- a/packages/jsts/src/rules/S4830/unit.test.ts +++ b/packages/jsts/src/rules/S4830/unit.test.ts @@ -16,15 +16,16 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S4830', () => { - const ruleTesterJs = new RuleTester(); + it('S4830', () => { + const ruleTesterJs = new RuleTester(); - const testCasesHttps = { - valid: [ - { - code: ` + const testCasesHttps = { + valid: [ + { + code: ` const https = require('https'); var options = { @@ -45,9 +46,9 @@ describe('S4830', () => { }); }); // Compliant `, - }, - { - code: ` + }, + { + code: ` const https = require('https'); var options = { @@ -67,15 +68,15 @@ describe('S4830', () => { }); }); // Compliant `, - }, - { - code: ` + }, + { + code: ` const https = require('https'); var req = https.request(); `, - }, - { - code: ` + }, + { + code: ` const https = require('https'); var options = getOptions(); @@ -86,11 +87,11 @@ describe('S4830', () => { }); }); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const https = require('https'); const constants = require('constants'); @@ -107,36 +108,36 @@ describe('S4830', () => { res.on('data', (d) => {}); }); // Noncompliant `, - errors: [ - { - line: 14, - endLine: 14, - column: 15, - endColumn: 28, - message: JSON.stringify({ - message: 'Enable server certificate validation on this SSL/TLS connection.', - secondaryLocations: [ - { - column: 18, - line: 5, - endColumn: 5, - endLine: 12, - }, - { - message: 'Set "rejectUnauthorized" to "true".', - column: 6, - line: 11, - endColumn: 31, - endLine: 11, - }, - ], - }), - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + line: 14, + endLine: 14, + column: 15, + endColumn: 28, + message: JSON.stringify({ + message: 'Enable server certificate validation on this SSL/TLS connection.', + secondaryLocations: [ + { + column: 18, + line: 5, + endColumn: 5, + endLine: 12, + }, + { + message: 'Set "rejectUnauthorized" to "true".', + column: 6, + line: 11, + endColumn: 31, + endLine: 11, + }, + ], + }), + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const https = require('node:https'); const constants = require('node:constants'); @@ -153,14 +154,14 @@ describe('S4830', () => { res.on('data', (d) => {}); }); // Noncompliant `, - errors: 1, - }, - ], - }; - const testCasesRequest = { - valid: [ - { - code: ` + errors: 1, + }, + ], + }; + const testCasesRequest = { + valid: [ + { + code: ` const request = require('request'); var socket = request.get({ @@ -169,9 +170,9 @@ describe('S4830', () => { rejectUnauthorized: true }); // Compliant `, - }, - { - code: ` + }, + { + code: ` const request = require('request'); var socket = request.get({ @@ -180,11 +181,11 @@ describe('S4830', () => { //rejectUnauthorized: true // by default is set to true }); // Compliant `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const request = require('request'); var socket = request.get({ @@ -193,25 +194,25 @@ describe('S4830', () => { rejectUnauthorized: false // Noncompliant }); // Noncompliant `, - errors: 1, - }, - ], - }; - const testCasesTls = { - valid: [ - { - code: ` + errors: 1, + }, + ], + }; + const testCasesTls = { + valid: [ + { + code: ` var options = { rejectUnauthorized: true }; var socket = tls.connect(443, "self-signed.badssl.com", options, () => {}); // Compliant `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const tls = require('tls'); var options = { @@ -219,10 +220,10 @@ describe('S4830', () => { }; var socket = tls.connect(443, "self-signed.badssl.com", options, () => {}); // Noncompliant `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const tls = require('node:tls'); var options = { @@ -230,23 +231,24 @@ describe('S4830', () => { }; var socket = tls.connect(443, "self-signed.badssl.com", options, () => {}); // Noncompliant `, - errors: 1, - }, - ], - }; - ruleTesterJs.run( - '[https] Server certificates should be verified during SSL⁄TLS connections', - rule, - testCasesHttps, - ); - ruleTesterJs.run( - '[request] Server certificates should be verified during SSL⁄TLS connections', - rule, - testCasesRequest, - ); - ruleTesterJs.run( - '[tls] Server certificates should be verified during SSL⁄TLS connections', - rule, - testCasesTls, - ); + errors: 1, + }, + ], + }; + ruleTesterJs.run( + '[https] Server certificates should be verified during SSL⁄TLS connections', + rule, + testCasesHttps, + ); + ruleTesterJs.run( + '[request] Server certificates should be verified during SSL⁄TLS connections', + rule, + testCasesRequest, + ); + ruleTesterJs.run( + '[tls] Server certificates should be verified during SSL⁄TLS connections', + rule, + testCasesTls, + ); + }); }); diff --git a/packages/jsts/src/rules/S5042/unit.test.ts b/packages/jsts/src/rules/S5042/unit.test.ts index 428a40b366..d3a2bf03c6 100644 --- a/packages/jsts/src/rules/S5042/unit.test.ts +++ b/packages/jsts/src/rules/S5042/unit.test.ts @@ -16,23 +16,24 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5042', () => { - const ruleTesterTs = new RuleTester(); + it('S5042', () => { + const ruleTesterTs = new RuleTester(); - /* + /* +-+-+-+ |T|A|R| +-+-+-+ */ - ruleTesterTs.run( - 'Expanding archive files without controlling resource consumption is security sensitive [tar library]', - rule, - { - valid: [ - { - code: ` + ruleTesterTs.run( + 'Expanding archive files without controlling resource consumption is security sensitive [tar library]', + rule, + { + valid: [ + { + code: ` const tar = require('tar'); tar.x({ @@ -43,211 +44,212 @@ describe('S5042', () => { tar.x(); tar.x({file: 'foo.tar.gz', ...other}); tar.x({file: 'foo.tar.gz', 'filter': somePredicate});`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const tar = require('tar'); tar.x({ // Sensitive file: 'foo.tar.gz' });`, - errors: [ - { - message: 'Make sure that expanding this archive file is safe here.', - line: 4, - column: 9, - endLine: 4, - endColumn: 14, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Make sure that expanding this archive file is safe here.', + line: 4, + column: 9, + endLine: 4, + endColumn: 14, + }, + ], + }, + { + code: ` import * as tar from 'tar'; tar.x({ // Sensitive file: 'foo.tar.gz' });`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` import {x} from 'tar'; x({ // FN file: 'foo.tar.gz' });`, - errors: 1, - }, - ], - }, - ); + errors: 1, + }, + ], + }, + ); - /* + /* +-+-+-+-+-+-+-+ |A|D|M|-|Z|I|P| +-+-+-+-+-+-+-+ */ - ruleTesterTs.run( - 'Expanding archive files without controlling resource consumption is security sensitive [adm-zip library]', - rule, - { - valid: [ - { - code: ` + ruleTesterTs.run( + 'Expanding archive files without controlling resource consumption is security sensitive [adm-zip library]', + rule, + { + valid: [ + { + code: ` const AdmZip = require('adm-zip'); let zip = new AdmZip("./foo.zip"); zip.getEntries();`, - }, - { - code: ` + }, + { + code: ` const AdmZip = require('other-lib'); let zip = new AdmZip("./foo.zip"); zip.extractAllTo(".");`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const AdmZip = require('adm-zip'); let zip = new AdmZip("./foo.zip"); zip.extractAllTo("."); // Sensitive`, - errors: [ - { - message: 'Make sure that expanding this archive file is safe here.', - line: 5, - column: 9, - endLine: 5, - endColumn: 25, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Make sure that expanding this archive file is safe here.', + line: 5, + column: 9, + endLine: 5, + endColumn: 25, + }, + ], + }, + { + code: ` import * as AdmZip from 'adm-zip'; let zip = new AdmZip("./foo.zip"); zip.extractAllTo("."); // Sensitive`, - errors: 1, - }, - ], - }, - ); + errors: 1, + }, + ], + }, + ); - /** + /** +-+-+-+-+-+ |J|S|Z|I|P| +-+-+-+-+-+ */ - ruleTesterTs.run( - 'Expanding archive files without controlling resource consumption is security sensitive [jszip library]', - rule, - { - valid: [ - { - code: ` + ruleTesterTs.run( + 'Expanding archive files without controlling resource consumption is security sensitive [jszip library]', + rule, + { + valid: [ + { + code: ` const JSZip = require("jszip"); JSZip.other();`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const JSZip = require("jszip"); JSZip.loadAsync(data);`, - errors: [ - { - message: 'Make sure that expanding this archive file is safe here.', - line: 3, - column: 9, - endLine: 3, - endColumn: 24, - }, - ], - }, - ], - }, - ); + errors: [ + { + message: 'Make sure that expanding this archive file is safe here.', + line: 3, + column: 9, + endLine: 3, + endColumn: 24, + }, + ], + }, + ], + }, + ); - /** + /** +-+-+-+-+-+ |Y|A|U|Z|L| +-+-+-+-+-+ */ - ruleTesterTs.run( - 'Expanding archive files without controlling resource consumption is security sensitive [yauzl library]', - rule, - { - valid: [ - { - code: ` + ruleTesterTs.run( + 'Expanding archive files without controlling resource consumption is security sensitive [yauzl library]', + rule, + { + valid: [ + { + code: ` const yauzl = require("yauzl"); yauzl.other();`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const yauzl = require("yauzl"); yauzl.open('foo.zip', cb);`, - errors: [ - { - message: 'Make sure that expanding this archive file is safe here.', - line: 3, - column: 9, - endLine: 3, - endColumn: 19, - }, - ], - }, - ], - }, - ); - /** + errors: [ + { + message: 'Make sure that expanding this archive file is safe here.', + line: 3, + column: 9, + endLine: 3, + endColumn: 19, + }, + ], + }, + ], + }, + ); + /** +-+-+-+-+-+-+-+-+-+-+-+ |E|X|T|R|A|C|T|-|Z|I|P| +-+-+-+-+-+-+-+-+-+-+-+ */ - ruleTesterTs.run( - 'Expanding archive files without controlling resource consumption is security sensitive [extract-zip library]', - rule, - { - valid: [ - { - code: ` + ruleTesterTs.run( + 'Expanding archive files without controlling resource consumption is security sensitive [extract-zip library]', + rule, + { + valid: [ + { + code: ` const extract = require('extract-zip'); extract('foo.zip', {onEntry: cb}); extract(); extract('foo.zip');`, - }, - { - code: ` + }, + { + code: ` const extract = require('other'); extract('foo.zip', {});`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const extract = require('extract-zip'); extract('foo.zip', {});`, - errors: [ - { - message: 'Make sure that expanding this archive file is safe here.', - line: 3, - column: 9, - endLine: 3, - endColumn: 16, - }, - ], - }, - ], - }, - ); + errors: [ + { + message: 'Make sure that expanding this archive file is safe here.', + line: 3, + column: 9, + endLine: 3, + endColumn: 16, + }, + ], + }, + ], + }, + ); + }); }); diff --git a/packages/jsts/src/rules/S5332/unit.test.ts b/packages/jsts/src/rules/S5332/unit.test.ts index 6471f2291f..a53fc5cf67 100644 --- a/packages/jsts/src/rules/S5332/unit.test.ts +++ b/packages/jsts/src/rules/S5332/unit.test.ts @@ -16,14 +16,15 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5332', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Using clear-text protocols is security-sensitive', rule, { - valid: [ - { - code: ` + it('S5332', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Using clear-text protocols is security-sensitive', rule, { + valid: [ + { + code: ` // Non sensitive url scheme url = "https://"; url = "sftp://"; @@ -41,66 +42,66 @@ describe('S5332', () => { url = "http://127.0.0.1"; url = "ftp://user@localhost"; `, - }, - { - code: ` + }, + { + code: ` const nodemailer = require("nodemailer"); let transporter = nodemailer.createTransport({ secure: true, }); `, - }, - { - code: ` + }, + { + code: ` const nodemailer = require("nodemailer"); let transporter = nodemailer.createTransport(); `, - }, - { - code: ` + }, + { + code: ` const nodemailer = require("nodemailer"); let transporter = nodemailer.createTransport({ requireTLS: true, }); `, - }, - { - code: ` + }, + { + code: ` const nodemailer = require("nodemailer"); let transporter = nodemailer.createTransport({ port: 465, // Compliant (port 465 enables encryption automatically) }); `, - }, - { - code: ` + }, + { + code: ` var Client = require('ftp'); var c = new Client(); c.connect({ 'secure': true }); `, - }, - { - code: ` + }, + { + code: ` var Client = require('ftp'); var c = new Client(); c.connect(); `, - }, - { - code: ` + }, + { + code: ` require('some-module'); require(); import * as estree from 'estree'; `, - }, - { - code: ` + }, + { + code: ` const nodemailer = require("nodemailer"); let transporter = nodemailer.createTransport({ // OK @@ -109,16 +110,16 @@ describe('S5332', () => { port: 1234 }); `, - }, - { - code: ` + }, + { + code: ` url = "http://"; url = "ftp://"; url = "telnet://"; `, - }, - { - code: ` + }, + { + code: ` url = "http://example.example"; url = "http://subdomain.example.example"; url = "http://example.com"; @@ -130,20 +131,20 @@ describe('S5332', () => { url = "http://test.com"; url = "http://someSubdomain.test.com"; `, - }, - { - code: ` + }, + { + code: ` url = "http://xmlns.com"; `, - }, - { - code: ` + }, + { + code: ` url = 'http://'.replace('', foo); url = 'http://'.replace('', foo) + bar; `, - }, - { - code: ` + }, + { + code: ` import * as ses from '@aws-sdk/client-ses'; import nodemailer from 'nodemailer'; @@ -154,46 +155,46 @@ describe('S5332', () => { aws: ses, }, });`, - }, - { - code: ` + }, + { + code: ` url = 'http://schemas.microsoft.com/ws/2008/06/identity/claims/groups'; url = 'http://schemas.microsoft.com/identity/claims/displayname'; url = 'http://schemas.microsoft.com'; `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` url = "http://192.168.0.1"; url = "http://10.1.1.123"; url = "http://subdomain.exemple.com"; url = "ftp://anonymous@exemple.com"; url = "telnet://anonymous@exemple.com"; `, - errors: 5, - }, - { - code: ` + errors: 5, + }, + { + code: ` var Client = require('ftp'); var c = new Client(); c.connect({ 'secure': false }); `, - errors: [ - { - message: 'Using ftp protocol is insecure. Use sftp, scp or ftps instead.', - line: 4, - endLine: 4, - column: 7, - endColumn: 16, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Using ftp protocol is insecure. Use sftp, scp or ftps instead.', + line: 4, + endLine: 4, + column: 7, + endColumn: 16, + }, + ], + }, + { + code: ` const nodemailer = require("nodemailer"); let transporter = nodemailer.createTransport({ @@ -202,50 +203,50 @@ describe('S5332', () => { port: 1234 }); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` require('telnet-client'); import * as telnet from 'telnet-client'; `, - errors: 2, - }, - { - code: ` + errors: 2, + }, + { + code: ` url = "http://someUrl.com?url=test.com"; `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` url = "http://someSubdomain.xmlns.com"; url = "http://someUrl.com?url=xmlns.com"; `, - errors: 2, - }, - { - code: ` + errors: 2, + }, + { + code: ` url = 'http://' + something; `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` url = "http://0001::1"; url = "http://dead:beef::1"; url = "http://::dead:beef:1"; `, - errors: 3, - }, - { - code: ` + errors: 3, + }, + { + code: ` url = "http://::1"; // FP - url from Node.js is not able to parse IPV6 loopback address `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` import * as ses from '@aws-sdk/client-ses'; import * as fakeSes from 'fake-client-ses'; import nodemailer from 'nodemailer'; @@ -295,8 +296,9 @@ describe('S5332', () => { }, }); `, - errors: 7, - }, - ], + errors: 7, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S5443/unit.test.ts b/packages/jsts/src/rules/S5443/unit.test.ts index d195cea448..42fd9cb3f5 100644 --- a/packages/jsts/src/rules/S5443/unit.test.ts +++ b/packages/jsts/src/rules/S5443/unit.test.ts @@ -16,14 +16,15 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5443', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Using publicly writable directories is security-sensitive', rule, { - valid: [ - { - code: ` + it('S5443', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Using publicly writable directories is security-sensitive', rule, { + valid: [ + { + code: ` const tmp = require('tmp'); const tmp_promise = require('tmp-promise'); @@ -47,33 +48,33 @@ describe('S5443', () => { tmpDir = something.env.TMP; tmpDir = process.env.other; `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` tmpDir = process.env.TMPDIR; tmpFile = "/tmp/f"; `, - errors: [ - { - message: 'Make sure publicly writable directories are used safely here.', - line: 2, - endLine: 2, - column: 16, - endColumn: 34, - }, - { - message: 'Make sure publicly writable directories are used safely here.', - line: 3, - endLine: 3, - column: 17, - endColumn: 25, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Make sure publicly writable directories are used safely here.', + line: 2, + endLine: 2, + column: 16, + endColumn: 34, + }, + { + message: 'Make sure publicly writable directories are used safely here.', + line: 3, + endLine: 3, + column: 17, + endColumn: 25, + }, + ], + }, + { + code: ` tmpDir = process.env.TMP; tmpDir = process.env.TEMPDIR; tmpDir = process.env.TEMP; @@ -94,8 +95,9 @@ describe('S5443', () => { tmpFile = "C:\\TEMP"; tmpFile = "C:\\TMP"; `, - errors: 18, - }, - ], + errors: 18, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S5527/unit.test.ts b/packages/jsts/src/rules/S5527/unit.test.ts index 59e252eea0..5c50e878dd 100644 --- a/packages/jsts/src/rules/S5527/unit.test.ts +++ b/packages/jsts/src/rules/S5527/unit.test.ts @@ -16,15 +16,16 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5527', () => { - const ruleTesterJs = new RuleTester(); + it('S5527', () => { + const ruleTesterJs = new RuleTester(); - const testCasesHttps = { - valid: [ - { - code: ` + const testCasesHttps = { + valid: [ + { + code: ` const https = require('https'); const constants = require('constants'); var options = { @@ -46,9 +47,9 @@ describe('S5527', () => { res.on('data', (d) => {}); }); // Compliant: rejectUnauthorized to true and some checks inside checkServerIdentity `, - }, - { - code: ` + }, + { + code: ` const https = require('https'); const constants = require('constants'); var options = { @@ -68,9 +69,9 @@ describe('S5527', () => { res.on('data', (d) => {}); }); // Compliant: rejectUnauthorized is true by default and some checks inside checkServerIdentity `, - }, - { - code: ` + }, + { + code: ` const https = require('https'); const constants = require('constants'); var options = { @@ -85,15 +86,15 @@ describe('S5527', () => { res.on('data', (d) => {}); }); // Compliant: rejectUnauthorized is true by default and default checkServerIdentity `, - }, - { - code: ` + }, + { + code: ` const https = require('https'); var req = https.request(); `, - }, - { - code: ` + }, + { + code: ` const https = require('https'); var options = {hostname: 'wrong.host.badssl.com',} if (x) { @@ -101,9 +102,9 @@ describe('S5527', () => { } var req = https.request(options, (res) => {}); `, - }, - { - code: ` + }, + { + code: ` const https = require('https'); rejectUnauthorized = false; if (x) { @@ -112,15 +113,15 @@ describe('S5527', () => { var options = {rejectUnauthorized}; var req = https.request(options, (res) => {}); `, - }, - { - code: ` + }, + { + code: ` const https = require('https'); https.unknown(); `, - }, - { - code: ` + }, + { + code: ` const https = require('https'); const constants = require('constants'); @@ -137,9 +138,9 @@ describe('S5527', () => { res.on('data', (d) => {}); }); `, - }, - { - code: ` + }, + { + code: ` const https = require('https'); const constants = require('constants'); @@ -160,11 +161,11 @@ describe('S5527', () => { res.on('data', (d) => {}); }); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const https = require('https'); const constants = require('constants'); @@ -187,36 +188,36 @@ describe('S5527', () => { res.on('data', (d) => {}); }); // Noncompliant: rejectUnauthorized is false `, - errors: [ - { - line: 20, - endLine: 20, - column: 17, - endColumn: 30, - message: JSON.stringify({ - message: 'Enable server hostname verification on this SSL/TLS connection.', - secondaryLocations: [ - { - column: 20, - line: 5, - endColumn: 7, - endLine: 18, - }, - { - message: 'Set "rejectUnauthorized" to "true".', - column: 8, - line: 11, - endColumn: 33, - endLine: 11, - }, - ], - }), - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + line: 20, + endLine: 20, + column: 17, + endColumn: 30, + message: JSON.stringify({ + message: 'Enable server hostname verification on this SSL/TLS connection.', + secondaryLocations: [ + { + column: 20, + line: 5, + endColumn: 7, + endLine: 18, + }, + { + message: 'Set "rejectUnauthorized" to "true".', + column: 8, + line: 11, + endColumn: 33, + endLine: 11, + }, + ], + }), + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const https = require('node:https'); const constants = require('node:constants'); @@ -239,10 +240,10 @@ describe('S5527', () => { res.on('data', (d) => {}); }); // Noncompliant: rejectUnauthorized is false `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const https = require('https'); const constants = require('constants'); @@ -259,35 +260,35 @@ describe('S5527', () => { res.on('data', (d) => {}); }); // Noncompliant `, - errors: [ - { - line: 14, - endLine: 14, - column: 17, - endColumn: 30, - message: JSON.stringify({ - message: 'Enable server hostname verification on this SSL/TLS connection.', - secondaryLocations: [ - { - column: 20, - line: 5, - endColumn: 7, - endLine: 12, - }, - { - column: 8, - line: 11, - endColumn: 42, - endLine: 11, - }, - ], - }), - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + line: 14, + endLine: 14, + column: 17, + endColumn: 30, + message: JSON.stringify({ + message: 'Enable server hostname verification on this SSL/TLS connection.', + secondaryLocations: [ + { + column: 20, + line: 5, + endColumn: 7, + endLine: 12, + }, + { + column: 8, + line: 11, + endColumn: 42, + endLine: 11, + }, + ], + }), + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const https = require('https'); const constants = require('constants'); @@ -308,15 +309,15 @@ describe('S5527', () => { res.on('data', (d) => {}); }); // Noncompliant `, - errors: 1, - }, - ], - }; + errors: 1, + }, + ], + }; - const testCasesRequest = { - valid: [ - { - code: ` + const testCasesRequest = { + valid: [ + { + code: ` const request = require('request'); var socket = request.get({ @@ -331,9 +332,9 @@ describe('S5527', () => { } }); `, - }, - { - code: ` + }, + { + code: ` const request = require('request'); var socket = request.get({ @@ -347,9 +348,9 @@ describe('S5527', () => { } }); `, - }, - { - code: ` + }, + { + code: ` const request = require('request'); var socket = request.get({ @@ -357,17 +358,17 @@ describe('S5527', () => { secureProtocol: 'TLSv1_2_method' }); `, - }, - { - code: ` + }, + { + code: ` const request = require('request'); request.unknown(); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const request = require('request'); var socket = request.get({ @@ -382,30 +383,30 @@ describe('S5527', () => { } }); // Noncompliant: rejectUnauthorized to true `, - errors: [ - { - line: 4, - endLine: 4, - column: 20, - endColumn: 31, - message: JSON.stringify({ - message: 'Enable server hostname verification on this SSL/TLS connection.', - secondaryLocations: [ - { - message: 'Set "rejectUnauthorized" to "true".', - column: 8, - line: 7, - endColumn: 33, - endLine: 7, - }, - ], - }), - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + line: 4, + endLine: 4, + column: 20, + endColumn: 31, + message: JSON.stringify({ + message: 'Enable server hostname verification on this SSL/TLS connection.', + secondaryLocations: [ + { + message: 'Set "rejectUnauthorized" to "true".', + column: 8, + line: 7, + endColumn: 33, + endLine: 7, + }, + ], + }), + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const request = require('request'); var socket = request.get({ @@ -414,10 +415,10 @@ describe('S5527', () => { checkServerIdentity: function() {} // Noncompliant: there is no test cases }); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const request = require('request'); var socket = request.get({ @@ -428,15 +429,15 @@ describe('S5527', () => { } // Noncompliant: there is no test cases }); `, - errors: 1, - }, - ], - }; + errors: 1, + }, + ], + }; - const testCasesTls = { - valid: [ - { - code: ` + const testCasesTls = { + valid: [ + { + code: ` const tls = require('tls'); var options = { @@ -454,9 +455,9 @@ describe('S5527', () => { process.stdin.resume(); }); `, - }, - { - code: ` + }, + { + code: ` const tls = require('tls'); var options = { @@ -473,17 +474,17 @@ describe('S5527', () => { process.stdin.resume(); }); `, - }, - { - code: ` + }, + { + code: ` const tls = require('tls'); tls.unknown(); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const tls = require('tls'); var options = { @@ -501,10 +502,10 @@ describe('S5527', () => { process.stdin.resume(); }); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const tls = require('node:tls'); var options = { @@ -522,10 +523,10 @@ describe('S5527', () => { process.stdin.resume(); }); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const tls = require('tls'); var options = { @@ -537,26 +538,27 @@ describe('S5527', () => { process.stdin.resume(); }); `, - errors: 1, - }, - ], - }; + errors: 1, + }, + ], + }; - ruleTesterJs.run( - '[JS-https] Server hostnames should be verified during SSL/TLS connections', - rule, - testCasesHttps, - ); + ruleTesterJs.run( + '[JS-https] Server hostnames should be verified during SSL/TLS connections', + rule, + testCasesHttps, + ); - ruleTesterJs.run( - '[JS-request] Server hostnames should be verified during SSL/TLS connections', - rule, - testCasesRequest, - ); + ruleTesterJs.run( + '[JS-request] Server hostnames should be verified during SSL/TLS connections', + rule, + testCasesRequest, + ); - ruleTesterJs.run( - '[JS-tls] Server hostnames should be verified during SSL/TLS connections', - rule, - testCasesTls, - ); + ruleTesterJs.run( + '[JS-tls] Server hostnames should be verified during SSL/TLS connections', + rule, + testCasesTls, + ); + }); }); diff --git a/packages/jsts/src/rules/S5542/unit.test.ts b/packages/jsts/src/rules/S5542/unit.test.ts index b8e731df90..a2fe1d3593 100644 --- a/packages/jsts/src/rules/S5542/unit.test.ts +++ b/packages/jsts/src/rules/S5542/unit.test.ts @@ -16,13 +16,14 @@ */ import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5542', () => { - const testCases = { - valid: [ - { - code: ` + it('S5542', () => { + const testCases = { + valid: [ + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); @@ -49,9 +50,9 @@ describe('S5542', () => { crypto.createCipheriv("RC4-HMAC-MD5", key, ""); crypto.createCipheriv("SEED-CFB", key, iv); `, - }, - { - code: ` + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); @@ -61,316 +62,317 @@ describe('S5542', () => { } crypto.createCipheriv(algorithm, key, iv); `, - }, - { - code: ` + }, + { + code: ` const crypto = require('crypto'); crypto.createCipheriv(); `, - }, - { - code: ` + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); crypto.createCipheriv(); `, - }, - { - code: ` + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv(42, key, iv); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("AES-128-CBC", key, iv); `, - errors: [ - { - line: 5, - column: 29, - endLine: 5, - endColumn: 42, - message: 'Use a secure mode and padding scheme.', - }, - ], - }, - { - code: ` + errors: [ + { + line: 5, + column: 29, + endLine: 5, + endColumn: 42, + message: 'Use a secure mode and padding scheme.', + }, + ], + }, + { + code: ` const crypto = require('node:crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("AES-128-CBC", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); const algorithm = "AES-128-CBC"; crypto.createCipheriv(algorithm, key, iv); `, - errors: [ - { - line: 6, - column: 29, - endLine: 6, - endColumn: 38, - message: 'Use a secure mode and padding scheme.', - }, - ], - }, - { - code: ` + errors: [ + { + line: 6, + column: 29, + endLine: 6, + endColumn: 38, + message: 'Use a secure mode and padding scheme.', + }, + ], + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("AES-128-CBC-HMAC-SHA1", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("AES-128-CBC-HMAC-SHA256", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); crypto.createCipheriv("AES-128-ECB", key, ""); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("AES128", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("aes128", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); crypto.createCipheriv("AES-192-ECB", key, ""); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); crypto.createCipheriv("AES192", key, ""); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("AES-192-CBC", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("aes192", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("AES256", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("BF", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("blowfish", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("CAMELLIA128", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("CAMELLIA192", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("CAMELLIA256", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("CAST", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("DES", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("DES-EDE", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("DES-EDE3", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("DES3", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("DESX", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("RC2", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("RC2-40", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("RC2-64", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("RC2-128", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv("SEED", key, iv); `, - errors: 1, - }, - ], - }; + errors: 1, + }, + ], + }; - new DefaultParserRuleTester().run( - '[JS] Encryption algorithms should be used with secure mode and padding scheme', - rule, - testCases, - ); - new RuleTester().run( - '[TS] Encryption algorithms should be used with secure mode and padding scheme', - rule, - testCases, - ); + new DefaultParserRuleTester().run( + '[JS] Encryption algorithms should be used with secure mode and padding scheme', + rule, + testCases, + ); + new RuleTester().run( + '[TS] Encryption algorithms should be used with secure mode and padding scheme', + rule, + testCases, + ); + }); }); diff --git a/packages/jsts/src/rules/S5547/unit.test.ts b/packages/jsts/src/rules/S5547/unit.test.ts index eafa610fee..42d3f99fad 100644 --- a/packages/jsts/src/rules/S5547/unit.test.ts +++ b/packages/jsts/src/rules/S5547/unit.test.ts @@ -16,15 +16,16 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5547', () => { - const ruleTesterJs = new RuleTester(); + it('S5547', () => { + const ruleTesterJs = new RuleTester(); - ruleTesterJs.run('[JS] Cipher algorithms should be robust', rule, { - valid: [ - { - code: ` + ruleTesterJs.run('[JS] Cipher algorithms should be robust', rule, { + valid: [ + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); @@ -48,9 +49,9 @@ describe('S5547', () => { crypto.createCipheriv("SEED-CFB", key, iv); `, - }, - { - code: ` + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); @@ -60,56 +61,56 @@ describe('S5547', () => { } crypto.createCipheriv(algorithm, key, iv); `, - }, - { - code: ` + }, + { + code: ` const crypto = require('crypto'); crypto.createCipheriv(); `, - }, - { - code: ` + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); crypto.createCipheriv(); `, - }, - { - code: ` + }, + { + code: ` const crypto = require('crypto'); var key = crypto.randomBytes(16); var iv = Buffer.from(crypto.randomBytes(16)); crypto.createCipheriv(42, key, iv); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const crypto = require('crypto'); crypto.createCipheriv("DES", key, iv); `, - errors: [ - { - line: 4, - column: 29, - endLine: 4, - endColumn: 34, - message: 'Use a strong cipher algorithm.', - }, - ], - }, - { - code: ` + errors: [ + { + line: 4, + column: 29, + endLine: 4, + endColumn: 34, + message: 'Use a strong cipher algorithm.', + }, + ], + }, + { + code: ` const crypto = require('node:crypto'); crypto.createCipheriv("DES", key, iv); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const crypto = require('crypto'); crypto.createCipheriv("DES", key, iv); @@ -120,8 +121,9 @@ describe('S5547', () => { crypto.createCipheriv("BF", key, iv); crypto.createCipheriv("blowfish", key, iv); `, - errors: 7, - }, - ], + errors: 7, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S5604/unit.test.ts b/packages/jsts/src/rules/S5604/unit.test.ts index 0f7b3838c5..fd6a5a9a52 100644 --- a/packages/jsts/src/rules/S5604/unit.test.ts +++ b/packages/jsts/src/rules/S5604/unit.test.ts @@ -16,172 +16,174 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5604', () => { - const ruleTester = new RuleTester(); + it('S5604', () => { + const ruleTester = new RuleTester(); - const defaultOptions = [{ permissions: ['geolocation'] }]; + const defaultOptions = [{ permissions: ['geolocation'] }]; - ruleTester.run('', rule, { - valid: [ - { - code: `navigator.permissions.query({name:"foo"})`, - options: defaultOptions, - }, - { - code: `param => navigator.permissions.query(param)`, - options: defaultOptions, - }, - { - code: `navigator.permissions.query({other:"geolocation"})`, - options: defaultOptions, - }, - { - code: `navigator.permissions.query({name:42})`, - options: defaultOptions, - }, - { - code: `navigator.permissions.query({name:"microphone"})`, - options: defaultOptions, - }, - { - code: `navigator.permissions.query({name:"foo"})`, - options: [{ permissions: ['foo'] }], - }, - { - code: `navigator.geolocation.watchPosition()`, - options: [{ permissions: ['camera'] }], - }, - { - code: `navigator.mediaDevices.getUserMedia()`, - options: defaultOptions, - }, - { - code: `navigator.mediaDevices.getUserMedia({ audio: true })`, - options: [{ permissions: [] }], - }, - { - code: `param => navigator.mediaDevices.getUserMedia(param)`, - options: [{ permissions: ['camera'] }], - }, - { - code: `navigator.mediaDevices.getUserMedia({ other: true })`, - options: [{ permissions: ['camera'] }], - }, - { - code: `param => navigator.mediaDevices.getUserMedia({ ...param })`, - options: [{ permissions: ['camera'] }], - }, - { - code: `Notification.requestPermission()`, - options: defaultOptions, - }, - { - code: `new Notification()`, - options: defaultOptions, - }, - ], - invalid: [ - { - code: ` + ruleTester.run('', rule, { + valid: [ + { + code: `navigator.permissions.query({name:"foo"})`, + options: defaultOptions, + }, + { + code: `param => navigator.permissions.query(param)`, + options: defaultOptions, + }, + { + code: `navigator.permissions.query({other:"geolocation"})`, + options: defaultOptions, + }, + { + code: `navigator.permissions.query({name:42})`, + options: defaultOptions, + }, + { + code: `navigator.permissions.query({name:"microphone"})`, + options: defaultOptions, + }, + { + code: `navigator.permissions.query({name:"foo"})`, + options: [{ permissions: ['foo'] }], + }, + { + code: `navigator.geolocation.watchPosition()`, + options: [{ permissions: ['camera'] }], + }, + { + code: `navigator.mediaDevices.getUserMedia()`, + options: defaultOptions, + }, + { + code: `navigator.mediaDevices.getUserMedia({ audio: true })`, + options: [{ permissions: [] }], + }, + { + code: `param => navigator.mediaDevices.getUserMedia(param)`, + options: [{ permissions: ['camera'] }], + }, + { + code: `navigator.mediaDevices.getUserMedia({ other: true })`, + options: [{ permissions: ['camera'] }], + }, + { + code: `param => navigator.mediaDevices.getUserMedia({ ...param })`, + options: [{ permissions: ['camera'] }], + }, + { + code: `Notification.requestPermission()`, + options: defaultOptions, + }, + { + code: `new Notification()`, + options: defaultOptions, + }, + ], + invalid: [ + { + code: ` navigator.permissions.query({name:"geolocation"}) // ^^^^^^^^^^^^^^^^^^`, - options: defaultOptions, - errors: [ - { - message: 'Make sure the use of the geolocation is necessary.', - line: 2, - endLine: 2, - column: 36, - endColumn: 54, - }, - ], - }, - { - code: `navigator.permissions.query({name: "camera"})`, - options: [{ permissions: ['camera'] }], - errors: 1, - }, - { - code: `navigator.permissions.query({name: "microphone"})`, - options: [{ permissions: ['microphone'] }], - errors: [ - { - message: 'Make sure the use of the microphone is necessary.', - }, - ], - }, - { - code: `navigator.permissions.query({name: "notifications"})`, - options: [{ permissions: ['notifications'] }], - errors: 1, - }, - { - code: `navigator.permissions.query({name: "persistent-storage"})`, - options: [{ permissions: ['persistent-storage'] }], - errors: 1, - }, - { - code: ` + options: defaultOptions, + errors: [ + { + message: 'Make sure the use of the geolocation is necessary.', + line: 2, + endLine: 2, + column: 36, + endColumn: 54, + }, + ], + }, + { + code: `navigator.permissions.query({name: "camera"})`, + options: [{ permissions: ['camera'] }], + errors: 1, + }, + { + code: `navigator.permissions.query({name: "microphone"})`, + options: [{ permissions: ['microphone'] }], + errors: [ + { + message: 'Make sure the use of the microphone is necessary.', + }, + ], + }, + { + code: `navigator.permissions.query({name: "notifications"})`, + options: [{ permissions: ['notifications'] }], + errors: 1, + }, + { + code: `navigator.permissions.query({name: "persistent-storage"})`, + options: [{ permissions: ['persistent-storage'] }], + errors: 1, + }, + { + code: ` navigator.geolocation.watchPosition() //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^`, - options: defaultOptions, - errors: [ - { - messageId: 'checkPermission', - column: 7, - endColumn: 42, - }, - ], - }, - { - code: `navigator.geolocation.getCurrentPosition()`, - options: defaultOptions, - errors: 1, - }, - { - code: ` + options: defaultOptions, + errors: [ + { + messageId: 'checkPermission', + column: 7, + endColumn: 42, + }, + ], + }, + { + code: `navigator.geolocation.getCurrentPosition()`, + options: defaultOptions, + errors: 1, + }, + { + code: ` navigator.mediaDevices.getUserMedia() // Compliant navigator.mediaDevices.getUserMedia({ audio: true, video: true }) // Sensitive for camera and microphone navigator.mediaDevices.getUserMedia({ audio: true, video: false }) // Sensitive for microphone navigator.mediaDevices.getUserMedia({ audio: false, video: { /* something */} }) // Sensitive for camera only`, - options: [{ permissions: ['camera', 'microphone'] }], - errors: [ - { - message: 'Make sure the use of the microphone and camera is necessary.', - line: 3, - }, - { - message: 'Make sure the use of the microphone is necessary.', - line: 4, - }, - { - message: 'Make sure the use of the camera is necessary.', - line: 5, - }, - ], - }, - { - code: `Notification.requestPermission()`, - options: [{ permissions: ['notifications'] }], - errors: 1, - }, - { - code: `new Notification()`, - options: [{ permissions: ['notifications'] }], - errors: 1, - }, - { - code: `navigator.storage.persist()`, - options: [{ permissions: ['persistent-storage'] }], - errors: 1, - }, - { - code: `navigator.storage.anyMethod()`, - options: [{ permissions: ['persistent-storage'] }], - errors: 1, - }, - ], + options: [{ permissions: ['camera', 'microphone'] }], + errors: [ + { + message: 'Make sure the use of the microphone and camera is necessary.', + line: 3, + }, + { + message: 'Make sure the use of the microphone is necessary.', + line: 4, + }, + { + message: 'Make sure the use of the camera is necessary.', + line: 5, + }, + ], + }, + { + code: `Notification.requestPermission()`, + options: [{ permissions: ['notifications'] }], + errors: 1, + }, + { + code: `new Notification()`, + options: [{ permissions: ['notifications'] }], + errors: 1, + }, + { + code: `navigator.storage.persist()`, + options: [{ permissions: ['persistent-storage'] }], + errors: 1, + }, + { + code: `navigator.storage.anyMethod()`, + options: [{ permissions: ['persistent-storage'] }], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S5659/unit.test.ts b/packages/jsts/src/rules/S5659/unit.test.ts index abc224bf99..b3feb861e3 100644 --- a/packages/jsts/src/rules/S5659/unit.test.ts +++ b/packages/jsts/src/rules/S5659/unit.test.ts @@ -16,40 +16,41 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5659', () => { - const ruleTesterJs = new RuleTester(); - const ruleTesterTs = new RuleTester(); + it('S5659', () => { + const ruleTesterJs = new RuleTester(); + const ruleTesterTs = new RuleTester(); - const testCases = { - valid: [ - { - code: ` + const testCases = { + valid: [ + { + code: ` const jwt = require('jsonwebtoken'); let token = jwt.sign({ foo: 'bar' }, key, { algorithm: 'RS256' }); `, - }, - { - code: ` + }, + { + code: ` const jwt = require('jsonwebtoken'); let token = jwt.sign({ foo: 'bar' }, key, { algorithm: 'HS256' }); `, - }, - { - code: ` + }, + { + code: ` const jwt = require('jsonwebtoken'); let token = jwt.sign({ foo: 'bar' }, key, { expiresIn: '30d' }); `, - }, - { - code: ` + }, + { + code: ` const jwt = unknown('jsonwebtoken'); let token = jwt.sign({ foo: 'bar' }, key, { algorithm: 'none' }); `, - }, - { - code: ` + }, + { + code: ` const jwt = require('jsonwebtoken'); let NONE = 'none'; if (x) { @@ -57,15 +58,15 @@ describe('S5659', () => { } jwt.sign(forgedtoken, key, { expiresIn: 360000 * 5, algorithm: NONE }, callbackcheck); `, - }, - { - code: ` + }, + { + code: ` const jwt = require('jsonwebtoken'); let token = jwt.sign('missing arguments'); `, - }, - { - code: ` + }, + { + code: ` const jwt = require('jsonwebtoken'); let options = { algorithm: 'RS256' }; if (x) { @@ -73,15 +74,15 @@ describe('S5659', () => { } let token = jwt.sign({ foo: 'bar' }, key, options); `, - }, - { - code: ` + }, + { + code: ` const jwt = require('jsonwebtoken'); jwt.verify(forgedtoken, key, { expiresIn: 360000 * 5, algorithms: ['RS256', 'HS256'] }, callbackcheck); `, - }, - { - code: ` + }, + { + code: ` const jwt = require('jsonwebtoken'); let NONE = 'none'; if (x) { @@ -89,9 +90,9 @@ describe('S5659', () => { } jwt.verify(forgedtoken, key, { expiresIn: 360000 * 5, algorithms: ['RS256', NONE] }, callbackcheck); `, - }, - { - code: ` + }, + { + code: ` const jwt = require('jsonwebtoken'); const algorithms = 'other'; if (x) { @@ -99,275 +100,276 @@ describe('S5659', () => { } jwt.verify(forgedtoken, key, { expiresIn: 360000 * 5, algorithms }, callbackcheck); `, - }, - { - code: ` + }, + { + code: ` const jwt = require('jsonwebtoken'); jwt.verify(forgedtoken, key, { expiresIn: 360000 * 5 }, callbackcheck);`, - }, - { - code: ` + }, + { + code: ` const jwt = require('jsonwebtoken'); const options = { expiresIn: 360000 * 5 }; jwt.verify(forgedtoken, key, options, callbackcheck);`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const jwt = require('jsonwebtoken'); let token = jwt.sign({ foo: 'bar' }, key, { algorithm: 'none' }); `, - errors: [ - { - message: JSON.stringify({ - message: 'Use only strong cipher algorithms when signing this JWT.', - secondaryLocations: [ - { - message: `The "algorithms" option should be defined and should not contain 'none'.`, - column: 48, - line: 3, - endColumn: 69, - endLine: 3, - }, - ], - }), - line: 3, - endLine: 3, - column: 19, - endColumn: 27, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: 'Use only strong cipher algorithms when signing this JWT.', + secondaryLocations: [ + { + message: `The "algorithms" option should be defined and should not contain 'none'.`, + column: 48, + line: 3, + endColumn: 69, + endLine: 3, + }, + ], + }), + line: 3, + endLine: 3, + column: 19, + endColumn: 27, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const jwt = require('jsonwebtoken'); const options = { algorithm: 'none' }; let token = jwt.sign({ foo: 'bar' }, key, options); `, - errors: [ - { - message: JSON.stringify({ - message: 'Use only strong cipher algorithms when signing this JWT.', - secondaryLocations: [ - { - message: `The "algorithms" option should be defined and should not contain 'none'.`, - column: 22, - line: 3, - endColumn: 43, - endLine: 3, - }, - { - message: `The "algorithms" option should be defined and should not contain 'none'.`, - column: 48, - line: 4, - endColumn: 55, - endLine: 4, - }, - ], - }), - line: 4, - endLine: 4, - column: 19, - endColumn: 27, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: 'Use only strong cipher algorithms when signing this JWT.', + secondaryLocations: [ + { + message: `The "algorithms" option should be defined and should not contain 'none'.`, + column: 22, + line: 3, + endColumn: 43, + endLine: 3, + }, + { + message: `The "algorithms" option should be defined and should not contain 'none'.`, + column: 48, + line: 4, + endColumn: 55, + endLine: 4, + }, + ], + }), + line: 4, + endLine: 4, + column: 19, + endColumn: 27, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const jwt = require('jsonwebtoken'); const NONE = 'none'; let token = jwt.sign({ foo: 'bar' }, key, { algorithm: NONE }); `, - errors: [ - { - message: JSON.stringify({ - message: 'Use only strong cipher algorithms when signing this JWT.', - secondaryLocations: [ - { - message: `The "algorithms" option should be defined and should not contain 'none'.`, - column: 48, - line: 4, - endColumn: 67, - endLine: 4, - }, - { - message: `The "algorithms" option should be defined and should not contain 'none'.`, - column: 19, - line: 3, - endColumn: 25, - endLine: 3, - }, - ], - }), - line: 4, - endLine: 4, - column: 19, - endColumn: 27, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: 'Use only strong cipher algorithms when signing this JWT.', + secondaryLocations: [ + { + message: `The "algorithms" option should be defined and should not contain 'none'.`, + column: 48, + line: 4, + endColumn: 67, + endLine: 4, + }, + { + message: `The "algorithms" option should be defined and should not contain 'none'.`, + column: 19, + line: 3, + endColumn: 25, + endLine: 3, + }, + ], + }), + line: 4, + endLine: 4, + column: 19, + endColumn: 27, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const jwt = require('jsonwebtoken'); const NONE = 'none'; const options = { algorithm: NONE }; let token = jwt.sign({ foo: 'bar' }, key, options); `, - errors: [ - { - message: JSON.stringify({ - message: 'Use only strong cipher algorithms when signing this JWT.', - secondaryLocations: [ - { - message: `The "algorithms" option should be defined and should not contain 'none'.`, - column: 22, - line: 4, - endColumn: 41, - endLine: 4, - }, - { - message: `The "algorithms" option should be defined and should not contain 'none'.`, - column: 48, - line: 5, - endColumn: 55, - endLine: 5, - }, - { - message: `The "algorithms" option should be defined and should not contain 'none'.`, - column: 19, - line: 3, - endColumn: 25, - endLine: 3, - }, - ], - }), - line: 5, - endLine: 5, - column: 19, - endColumn: 27, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: 'Use only strong cipher algorithms when signing this JWT.', + secondaryLocations: [ + { + message: `The "algorithms" option should be defined and should not contain 'none'.`, + column: 22, + line: 4, + endColumn: 41, + endLine: 4, + }, + { + message: `The "algorithms" option should be defined and should not contain 'none'.`, + column: 48, + line: 5, + endColumn: 55, + endLine: 5, + }, + { + message: `The "algorithms" option should be defined and should not contain 'none'.`, + column: 19, + line: 3, + endColumn: 25, + endLine: 3, + }, + ], + }), + line: 5, + endLine: 5, + column: 19, + endColumn: 27, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` let token = require('jsonwebtoken').sign({ foo: 'bar' }, key, { algorithm: 'none' }); `, - errors: [ - { - message: JSON.stringify({ - message: 'Use only strong cipher algorithms when signing this JWT.', - secondaryLocations: [ - { - message: `The "algorithms" option should be defined and should not contain 'none'.`, - column: 68, - line: 2, - endColumn: 89, - endLine: 2, - }, - ], - }), - line: 2, - endLine: 2, - column: 19, - endColumn: 47, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: 'Use only strong cipher algorithms when signing this JWT.', + secondaryLocations: [ + { + message: `The "algorithms" option should be defined and should not contain 'none'.`, + column: 68, + line: 2, + endColumn: 89, + endLine: 2, + }, + ], + }), + line: 2, + endLine: 2, + column: 19, + endColumn: 47, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const jwt = require('jsonwebtoken'); jwt.verify(forgedtoken, key, { expiresIn: 360000 * 5, algorithms: ['RS256', 'none'] }, callbackcheck); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const jwt = require('jsonwebtoken'); const algorithms = ['RS256', 'none']; jwt.verify(forgedtoken, key, { expiresIn: 360000 * 5, algorithms }, callbackcheck); `, - errors: [ - { - message: JSON.stringify({ - message: - 'Use only strong cipher algorithms when verifying the signature of this JWT.', - secondaryLocations: [ - { - message: `The "algorithms" option should be defined and should not contain 'none'.`, - column: 35, - line: 4, - endColumn: 72, - endLine: 4, - }, - { - message: `The "algorithms" option should be defined and should not contain 'none'.`, - column: 25, - line: 3, - endColumn: 42, - endLine: 3, - }, - ], - }), - line: 4, - endLine: 4, - column: 7, - endColumn: 17, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: + 'Use only strong cipher algorithms when verifying the signature of this JWT.', + secondaryLocations: [ + { + message: `The "algorithms" option should be defined and should not contain 'none'.`, + column: 35, + line: 4, + endColumn: 72, + endLine: 4, + }, + { + message: `The "algorithms" option should be defined and should not contain 'none'.`, + column: 25, + line: 3, + endColumn: 42, + endLine: 3, + }, + ], + }), + line: 4, + endLine: 4, + column: 7, + endColumn: 17, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const jwt = require('jsonwebtoken'); const NONE = 'none'; jwt.verify(forgedtoken, key, { expiresIn: 360000 * 5, algorithms: ['RS256', NONE] }, callbackcheck); `, - errors: [ - { - message: JSON.stringify({ - message: - 'Use only strong cipher algorithms when verifying the signature of this JWT.', - secondaryLocations: [ - { - message: `The "algorithms" option should be defined and should not contain 'none'.`, - column: 35, - line: 4, - endColumn: 89, - endLine: 4, - }, - ], - }), - line: 4, - endLine: 4, - column: 7, - endColumn: 17, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: + 'Use only strong cipher algorithms when verifying the signature of this JWT.', + secondaryLocations: [ + { + message: `The "algorithms" option should be defined and should not contain 'none'.`, + column: 35, + line: 4, + endColumn: 89, + endLine: 4, + }, + ], + }), + line: 4, + endLine: 4, + column: 7, + endColumn: 17, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const jwt = require('jsonwebtoken'); jwt.verify(forgedtoken, null, { expiresIn: 360000 * 500 }, callbackcheck);`, - errors: 1, - }, - ], - }; + errors: 1, + }, + ], + }; - ruleTesterJs.run( - '[JS] JWT should be signed and verified with strong cipher algorithms', - rule, - testCases, - ); - ruleTesterTs.run( - '[TS] JWT should be signed and verified with strong cipher algorithms', - rule, - testCases, - ); + ruleTesterJs.run( + '[JS] JWT should be signed and verified with strong cipher algorithms', + rule, + testCases, + ); + ruleTesterTs.run( + '[TS] JWT should be signed and verified with strong cipher algorithms', + rule, + testCases, + ); + }); }); diff --git a/packages/jsts/src/rules/S5689/unit.test.ts b/packages/jsts/src/rules/S5689/unit.test.ts index 53f0fc23fd..d99b7b89fd 100644 --- a/packages/jsts/src/rules/S5689/unit.test.ts +++ b/packages/jsts/src/rules/S5689/unit.test.ts @@ -16,70 +16,71 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5689', () => { - const ruleTester = new RuleTester(); - ruleTester.run( - 'Recovering fingerprints from web application technologies should not be possible', - rule, - { - valid: [ - { - code: ` + it('S5689', () => { + const ruleTester = new RuleTester(); + ruleTester.run( + 'Recovering fingerprints from web application technologies should not be possible', + rule, + { + valid: [ + { + code: ` const express = require('express'); const app = express(); app.disable("x-powered-by"); // Compliant `, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const hidePoweredBy = require('hide-powered-by'); const app = express(); app.use(hidePoweredBy()); // Compliant `, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const app = express(); app.set("x-powered-by", false); // Compliant `, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const app = express(); app.set("X-PoWeReD-bY", false); // Compliant `, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const app = express(); app.use(require('helmet')()); // Compliant `, - }, - { - code: ` + }, + { + code: ` import express from 'express'; import disableXPoweredBy from 'hide-powered-by'; const app = express(); app.use(disableXPoweredBy()); // Compliant `, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const app = express(); const helmet = require('helmet'); const h = helmet(); app.use(h); `, - }, - { - code: ` + }, + { + code: ` // middleware instance is saved to variable instead of directly passed to 'app.use()' const express = require('express'); const helmet = require('helmet'); @@ -87,38 +88,38 @@ describe('S5689', () => { const app = express(); app.use(helmetInstance); // compliant `, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const app = express(); configure(app); // app escapes, probably configured elsewhere. `, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const helmet = require('helmet'); const app = express(); app.use(helmet.hidePoweredBy()); `, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const app = express(); app.use(require('helmet').hidePoweredBy()); `, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const app = express(); app.use(a, b, [c, d, require('helmet')(), e, f], g, h); `, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const app = express(); const helmet = require('helmet'); @@ -130,26 +131,26 @@ describe('S5689', () => { ]; app.use(usefulStuff, securityMiddlewares, moreStuff); `, - }, - { - code: ` + }, + { + code: ` const { app } = apps[42]; // Compliant (not obviously an express-app, ignored) const app2 = apps[42]; const { subcomponent } = require('express')(); apps[42] = require('express')(); // Limitation: we don't keep track of 'app' here. `, - }, - { - code: ` + }, + { + code: ` const express = require('express'); module.exports.createExpressApp = function() { var appEscaping = express(); // should be compliant, because express object is returned from the function return appEscaping; }; `, - }, - { - code: ` + }, + { + code: ` const express = require('express'); function f() { return 42; // a return before the application is discovered, for coverage @@ -159,110 +160,110 @@ describe('S5689', () => { return appEscaping; }; `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const express = require('express'); const app = express(); // Noncompliant `, - errors: [ - { - message: - 'This framework implicitly discloses version information by default. Make sure it is safe here.', - line: 3, - endLine: 3, - column: 15, - endColumn: 18, - }, - ], - }, - { - code: ` + errors: [ + { + message: + 'This framework implicitly discloses version information by default. Make sure it is safe here.', + line: 3, + endLine: 3, + column: 15, + endColumn: 18, + }, + ], + }, + { + code: ` import express from 'express'; const app = express(); // Noncompliant `, - errors: [ - { - message: - 'This framework implicitly discloses version information by default. Make sure it is safe here.', - line: 3, - endLine: 3, - column: 15, - endColumn: 18, - }, - ], - }, - { - code: ` + errors: [ + { + message: + 'This framework implicitly discloses version information by default. Make sure it is safe here.', + line: 3, + endLine: 3, + column: 15, + endColumn: 18, + }, + ], + }, + { + code: ` const app = require('express')(); // Noncompliant `, - errors: [ - { - message: - 'This framework implicitly discloses version information by default. Make sure it is safe here.', - line: 2, - endLine: 2, - column: 15, - endColumn: 18, - }, - ], - }, - { - code: ` + errors: [ + { + message: + 'This framework implicitly discloses version information by default. Make sure it is safe here.', + line: 2, + endLine: 2, + column: 15, + endColumn: 18, + }, + ], + }, + { + code: ` const express = require('express'); const app = express(); app.set("x-powered-by", true); // Noncompliant `, - errors: [ - { - message: - 'Make sure disclosing the fingerprinting of this web technology is safe here.', - line: 3, - endLine: 3, - column: 15, - endColumn: 18, - }, - ], - }, - { - code: ` + errors: [ + { + message: + 'Make sure disclosing the fingerprinting of this web technology is safe here.', + line: 3, + endLine: 3, + column: 15, + endColumn: 18, + }, + ], + }, + { + code: ` const express = require('express'); const app = express(); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const express = require('express'); const theforce = require('the-force'); const app = express(); app.use(theforce()); // That doesn't help here. app.use(somethingunknown()); // That doesn't help either. `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const express = require('express'); const helmet = require('helmet'); const helmetInst = helmet(); const app = express(); // imported, but forgot to use helmet `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const express = require('express'); const app = express(); app.use(a, b, [c, d, require('sth-useless')(), e, f], g, h); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const express = require('express'); const app = express(); const securityMiddlewares = [ @@ -272,19 +273,20 @@ describe('S5689', () => { ]; app.use(usefulStuff, securityMiddlewares, something.unknown()); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const express = require('express'); module.exports.createExpressApp = function() { var appEscaping = express(); return appEscaping.someSubproperty; // that's not sufficient, does not count as escaped app. }; `, - errors: 1, - }, - ], - }, - ); + errors: 1, + }, + ], + }, + ); + }); }); diff --git a/packages/jsts/src/rules/S5691/unit.test.ts b/packages/jsts/src/rules/S5691/unit.test.ts index 776b7bb051..d96fbf1994 100644 --- a/packages/jsts/src/rules/S5691/unit.test.ts +++ b/packages/jsts/src/rules/S5691/unit.test.ts @@ -16,16 +16,17 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5691', () => { - const message = 'Make sure serving hidden files is safe here.'; + it('S5691', () => { + const message = 'Make sure serving hidden files is safe here.'; - const ruleTester = new RuleTester(); - ruleTester.run('Statically serving hidden files is security-sensitive', rule, { - valid: [ - { - code: ` + const ruleTester = new RuleTester(); + ruleTester.run('Statically serving hidden files is security-sensitive', rule, { + valid: [ + { + code: ` const express = require('express'); const serveStatic = require('serve-static'); @@ -49,11 +50,11 @@ app.use(serveStatic('public', app.use(serveStatic('public')); // Compliant by default app.use(serveStatic('public', { 'index': false })); // Compliant by default `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const express = require('express'); const serveStatic = require('serve-static'); let app = express(); @@ -62,18 +63,18 @@ app.use(serveStatic('public', 'dotfiles': 'allow' // Sensitive })); `, - errors: [ - { - message, - line: 7, - endLine: 7, - column: 23, - endColumn: 42, - }, - ], - }, - { - code: ` + errors: [ + { + message, + line: 7, + endLine: 7, + column: 23, + endColumn: 42, + }, + ], + }, + { + code: ` import serveStatic from 'serve-static'; let app = express(); const options = { @@ -82,16 +83,17 @@ const options = { }; app.use(serveStatic('public', options)); `, - errors: [ - { - message, - line: 6, - endLine: 6, - column: 3, - endColumn: 22, - }, - ], - }, - ], + errors: [ + { + message, + line: 6, + endLine: 6, + column: 3, + endColumn: 22, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S5693/unit.test.ts b/packages/jsts/src/rules/S5693/unit.test.ts index 747bbff254..c59e1e9104 100644 --- a/packages/jsts/src/rules/S5693/unit.test.ts +++ b/packages/jsts/src/rules/S5693/unit.test.ts @@ -16,23 +16,24 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5693', () => { - const ruleTester = new RuleTester(); - const options = [{ fileUploadSizeLimit: 8_000_000, standardSizeLimit: 2_000_000 }]; + it('S5693', () => { + const ruleTester = new RuleTester(); + const options = [{ fileUploadSizeLimit: 8_000_000, standardSizeLimit: 2_000_000 }]; - ruleTester.run('Allowing requests with excessive content length is security-sensitive', rule, { - valid: [ - { - code: ` + ruleTester.run('Allowing requests with excessive content length is security-sensitive', rule, { + valid: [ + { + code: ` const formidable = require('formidable'); const form = formidable(options); `, - options, - }, - { - code: ` + options, + }, + { + code: ` const multer = require('multer'); const upload = multer(options); const storage = multer.diskStorage({ @@ -44,19 +45,19 @@ describe('S5693', () => { } }); `, - options, - }, - { - code: ` + options, + }, + { + code: ` import { formidable } from 'formidable'; const form = formidable({}); // Ok, default is used which is less than parameter `, - options: [{ fileUploadSizeLimit: 250_000_000, standardSizeLimit: 2_000_000 }], - }, - ], - invalid: [ - { - code: ` + options: [{ fileUploadSizeLimit: 250_000_000, standardSizeLimit: 2_000_000 }], + }, + ], + invalid: [ + { + code: ` const formidableModule = require('formidable'); const { formidable } = require('formidable'); const { formidable: formidableAlias } = require('formidable'); @@ -68,11 +69,11 @@ describe('S5693', () => { const form4 = new IncomingForm(); // Noncompliant const form5 = new Formidable(); // Noncompliant `, - errors: 5, - options, - }, - { - code: ` + errors: 5, + options, + }, + { + code: ` import * as formidableModule from 'formidable'; import { formidable } from 'formidable'; import { IncomingForm } from 'formidable'; @@ -83,11 +84,11 @@ describe('S5693', () => { const form4 = new IncomingForm(); // Noncompliant const form5 = new Formidable(); // Noncompliant `, - errors: 4, - options, - }, - { - code: ` + errors: 4, + options, + }, + { + code: ` import { formidable } from 'formidable'; const form0 = formidable(); form0.maxFileSize = 42; // OK @@ -102,23 +103,23 @@ describe('S5693', () => { const form3 = formidable(); form3.maxFileSize = unknown; // OK `, - errors: [ - { - message: 'Make sure the content length limit is safe here.', - line: 7, - endLine: 7, - column: 7, - endColumn: 35, - }, - { - message: 'Make sure the content length limit is safe here.', - line: 11, - }, - ], - options, - }, - { - code: ` + errors: [ + { + message: 'Make sure the content length limit is safe here.', + line: 7, + endLine: 7, + column: 7, + endColumn: 35, + }, + { + message: 'Make sure the content length limit is safe here.', + line: 11, + }, + ], + options, + }, + { + code: ` import { formidable } from 'formidable'; const form0 = formidable({ maxFileSize: 42000000 }); // Noncompliant const options = { maxFileSize: 42000000 }; // Noncompliant @@ -133,31 +134,31 @@ describe('S5693', () => { const notLiteral = foo(); const formOk3 = formidable({ maxFileSize: notLiteral }); `, - errors: [ - { - message: 'Make sure the content length limit is safe here.', - line: 3, - endLine: 3, - column: 34, - endColumn: 55, - }, - { - message: 'Make sure the content length limit is safe here.', - line: 4, - }, - { - message: 'Make sure the content length limit is safe here.', - line: 6, - }, - { - message: 'Make sure the content length limit is safe here.', - line: 8, - }, - ], - options, - }, - { - code: ` + errors: [ + { + message: 'Make sure the content length limit is safe here.', + line: 3, + endLine: 3, + column: 34, + endColumn: 55, + }, + { + message: 'Make sure the content length limit is safe here.', + line: 4, + }, + { + message: 'Make sure the content length limit is safe here.', + line: 6, + }, + { + message: 'Make sure the content length limit is safe here.', + line: 8, + }, + ], + options, + }, + { + code: ` import * as multer from 'multer'; multer({ limits: { fileSize: 42000000 } }); // Noncompliant @@ -169,17 +170,17 @@ describe('S5693', () => { multer({ storage }); // Noncompliant multer({ limits: {} }); // Noncompliant `, - errors: [ - { messageId: 'safeLimit', line: 3 }, - { messageId: 'safeLimit', line: 5 }, - { messageId: 'safeLimit', line: 9 }, - { messageId: 'safeLimit', line: 10 }, - { messageId: 'safeLimit', line: 11 }, - ], - options, - }, - { - code: ` + errors: [ + { messageId: 'safeLimit', line: 3 }, + { messageId: 'safeLimit', line: 5 }, + { messageId: 'safeLimit', line: 9 }, + { messageId: 'safeLimit', line: 10 }, + { messageId: 'safeLimit', line: 11 }, + ], + options, + }, + { + code: ` import { json } from 'body-parser'; import * as bodyParser from 'body-parser'; bodyParser.json({ limits: 4000000}); // Noncompliant @@ -188,15 +189,15 @@ describe('S5693', () => { json({ limits: 2000000}); // 2mb is ok json(); // ok, default 100kb `, - errors: [ - { messageId: 'safeLimit', line: 4 }, - { messageId: 'safeLimit', line: 5, endLine: 5, column: 14, endColumn: 29 }, - { messageId: 'safeLimit', line: 6 }, - ], - options, - }, - { - code: ` + errors: [ + { messageId: 'safeLimit', line: 4 }, + { messageId: 'safeLimit', line: 5, endLine: 5, column: 14, endColumn: 29 }, + { messageId: 'safeLimit', line: 6 }, + ], + options, + }, + { + code: ` import * as bodyParser from 'body-parser' bodyParser.text({ limits: '4mb'}); // Noncompliant, second option parameter is used @@ -205,27 +206,28 @@ describe('S5693', () => { bodyParser.urlencoded({ limits: '1mb'}); // 1mb is ok bodyParser.urlencoded({ limits: 'invalid'}); `, - errors: [ - { messageId: 'safeLimit', line: 4 }, - { messageId: 'safeLimit', line: 5 }, - { messageId: 'safeLimit', line: 6 }, - ], - options, - }, - { - code: ` + errors: [ + { messageId: 'safeLimit', line: 4 }, + { messageId: 'safeLimit', line: 5 }, + { messageId: 'safeLimit', line: 6 }, + ], + options, + }, + { + code: ` const bodyParser = require('body-parser'); bodyParser.json(); // Noncompliant, default 100kb bodyParser.json({ notLimits: 10}); // Noncompliant bodyParser.json(unknown); `, - errors: [ - { messageId: 'safeLimit', line: 4 }, - { messageId: 'safeLimit', line: 5 }, - ], - options: [{ fileUploadSizeLimit: 0, standardSizeLimit: 1000 }], - }, - ], + errors: [ + { messageId: 'safeLimit', line: 4 }, + { messageId: 'safeLimit', line: 5 }, + ], + options: [{ fileUploadSizeLimit: 0, standardSizeLimit: 1000 }], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S5725/unit.test.ts b/packages/jsts/src/rules/S5725/unit.test.ts index 47572f19aa..2531c53ac0 100644 --- a/packages/jsts/src/rules/S5725/unit.test.ts +++ b/packages/jsts/src/rules/S5725/unit.test.ts @@ -16,47 +16,48 @@ */ import { rule } from './index.js'; import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5725', () => { - const ruleTesterJs = new DefaultParserRuleTester(); - const ruleTesterTs = new RuleTester(); + it('S5725', () => { + const ruleTesterJs = new DefaultParserRuleTester(); + const ruleTesterTs = new RuleTester(); - ruleTesterJs.run('No issues without types', rule, { - valid: [ - { - code: ` + ruleTesterJs.run('No issues without types', rule, { + valid: [ + { + code: ` var script = document.createElement("script"); script.src = "https://code.jquery.com/jquery-3.4.1.min.js"; // Sensitive script.crossOrigin = "anonymous"; document.head.appendChild(script); `, - }, - ], - invalid: [], - }); + }, + ], + invalid: [], + }); - ruleTesterTs.run('Disabling resource integrity features is security-sensitive', rule, { - valid: [ - { - code: ` + ruleTesterTs.run('Disabling resource integrity features is security-sensitive', rule, { + valid: [ + { + code: ` var script = document.createElement("script"); script.src = "https://code.jquery.com/jquery-3.4.1.min.js"; script.integrity = "sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="; // Compliant script.crossOrigin = "anonymous"; document.head.appendChild(script); `, - }, - { - code: ` + }, + { + code: ` var script = document.createElement("script"); script.src = getSource(); script.crossOrigin = "anonymous"; document.head.appendChild(script); `, - }, - { - code: ` + }, + { + code: ` var script = document.createElement("script"); script.src = "https://code.jquery.com/jquery-3.4.1.min.js"; if (x) { @@ -65,9 +66,9 @@ describe('S5725', () => { script.crossOrigin = "anonymous"; document.head.appendChild(script); `, - }, - { - code: ` + }, + { + code: ` var script = document.other("script"); script.src = "https://code.jquery.com/jquery-3.4.1.min.js"; if (x) { @@ -76,9 +77,9 @@ describe('S5725', () => { script.crossOrigin = "anonymous"; document.head.appendChild(script); `, - }, - { - code: ` + }, + { + code: ` var script = other.createElement("script"); script.src = "https://code.jquery.com/jquery-3.4.1.min.js"; if (x) { @@ -87,9 +88,9 @@ describe('S5725', () => { script.crossOrigin = "anonymous"; document.head.appendChild(script); `, - }, - { - code: ` + }, + { + code: ` // Coverage var script = getScript(); script.src = getSource(); @@ -97,9 +98,9 @@ describe('S5725', () => { script.crossOrigin = "anonymous"; document.head.appendChild(script); `, - }, - { - code: ` + }, + { + code: ` var script = document.createElement("script"); script.src = "https://code.jquery.com/jquery-3.4.1.min.js"; var other = script.src; @@ -107,51 +108,52 @@ describe('S5725', () => { script.crossOrigin = "anonymous"; document.head.appendChild(script); `, - }, - { - code: ` + }, + { + code: ` var script = document.createElement("other"); script.src = "https://code.jquery.com/jquery-3.4.1.min.js"; script.crossOrigin = "anonymous"; document.head.appendChild(script); `, - }, - { - code: ` + }, + { + code: ` if (cond) { var script = document.createElement( "script" ); script.src = "https://code.jquery.com/jquery-3.4.1.min.js"; // FN (missing variable) } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` var script = document.createElement("script"); script.src = "https://code.jquery.com/jquery-3.4.1.min.js"; // Sensitive script.crossOrigin = "anonymous"; document.head.appendChild(script); `, - errors: [ - { - line: 2, - endLine: 2, - column: 11, - endColumn: 52, - message: 'Make sure not using resource integrity feature is safe here.', - }, - ], - }, - { - code: ` + errors: [ + { + line: 2, + endLine: 2, + column: 11, + endColumn: 52, + message: 'Make sure not using resource integrity feature is safe here.', + }, + ], + }, + { + code: ` var script = document.createElement("script"); script.src = "//code.jquery.com/jquery-3.4.1.min.js"; // Sensitive script.crossOrigin = "anonymous"; document.head.appendChild(script); `, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S5728/unit.test.ts b/packages/jsts/src/rules/S5728/unit.test.ts index 8b90770044..182f6d0dc2 100644 --- a/packages/jsts/src/rules/S5728/unit.test.ts +++ b/packages/jsts/src/rules/S5728/unit.test.ts @@ -16,37 +16,41 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5728', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Disabling content security policy fetch directives is security-sensitive', rule, { - valid: [ + it('S5728', () => { + const ruleTester = new RuleTester(); + ruleTester.run( + 'Disabling content security policy fetch directives is security-sensitive', + rule, { - code: ` + valid: [ + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express();`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); app.use( helmet() );`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); const h = helmet(); app.use(h);`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -55,9 +59,9 @@ describe('S5728', () => { contentSecurityPolicy: true, }) );`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); module.exports = function (app) { app.use( @@ -66,9 +70,9 @@ describe('S5728', () => { }) ); }`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); module.exports = function (foo) { app.use( @@ -77,9 +81,9 @@ describe('S5728', () => { }) ); }`, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const app = express(); app.use( @@ -87,17 +91,17 @@ describe('S5728', () => { contentSecurityPolicy: false, }) );`, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const app = express(); app.use('/endpoint', callback);`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -106,29 +110,29 @@ describe('S5728', () => { contentSecurityPolicy: false, // Noncompliant }) );`, - errors: [ - { - message: JSON.stringify({ - message: `Make sure not enabling content security policy fetch directives is safe here.`, - secondaryLocations: [ - { - column: 12, - line: 7, - endColumn: 40, - endLine: 7, - }, - ], - }), - line: 5, - endLine: 9, - column: 9, - endColumn: 10, + errors: [ + { + message: JSON.stringify({ + message: `Make sure not enabling content security policy fetch directives is safe here.`, + secondaryLocations: [ + { + column: 12, + line: 7, + endColumn: 40, + endLine: 7, + }, + ], + }), + line: 5, + endLine: 9, + column: 9, + endColumn: 10, + }, + ], + options: ['sonar-runtime'], }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + { + code: ` const helmet = require('helmet'); module.exports = function (app) { app.use( @@ -137,29 +141,29 @@ describe('S5728', () => { }) ); }`, - errors: [ - { - message: JSON.stringify({ - message: `Make sure not enabling content security policy fetch directives is safe here.`, - secondaryLocations: [ - { - column: 14, - line: 6, - endColumn: 42, - endLine: 6, - }, - ], - }), - line: 4, - endLine: 8, - column: 11, - endColumn: 12, + errors: [ + { + message: JSON.stringify({ + message: `Make sure not enabling content security policy fetch directives is safe here.`, + secondaryLocations: [ + { + column: 14, + line: 6, + endColumn: 42, + endLine: 6, + }, + ], + }), + line: 4, + endLine: 8, + column: 11, + endColumn: 12, + }, + ], + options: ['sonar-runtime'], }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + { + code: ` const helmet = require('helmet'); module.exports.sensitiveCsp = function (app) { app.use( @@ -168,27 +172,29 @@ describe('S5728', () => { }) ); }`, - errors: [ - { - message: JSON.stringify({ - message: `Make sure not enabling content security policy fetch directives is safe here.`, - secondaryLocations: [ - { - column: 14, - line: 6, - endColumn: 42, - endLine: 6, - }, - ], - }), - line: 4, - endLine: 8, - column: 11, - endColumn: 12, + errors: [ + { + message: JSON.stringify({ + message: `Make sure not enabling content security policy fetch directives is safe here.`, + secondaryLocations: [ + { + column: 14, + line: 6, + endColumn: 42, + endLine: 6, + }, + ], + }), + line: 4, + endLine: 8, + column: 11, + endColumn: 12, + }, + ], + options: ['sonar-runtime'], }, ], - options: ['sonar-runtime'], }, - ], + ); }); }); diff --git a/packages/jsts/src/rules/S5730/unit.test.ts b/packages/jsts/src/rules/S5730/unit.test.ts index cae35e0b6b..ef50482843 100644 --- a/packages/jsts/src/rules/S5730/unit.test.ts +++ b/packages/jsts/src/rules/S5730/unit.test.ts @@ -16,14 +16,15 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5730', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Allowing mixed-content is security-sensitive', rule, { - valid: [ - { - code: ` + it('S5730', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Allowing mixed-content is security-sensitive', rule, { + valid: [ + { + code: ` const csp = require('helmet-csp') const express = require('express'); const app = express(); @@ -34,9 +35,9 @@ describe('S5730', () => { } }) );`, - }, - { - code: ` + }, + { + code: ` const csp = require('helmet-csp') const express = require('express'); const app = express(); @@ -47,27 +48,27 @@ describe('S5730', () => { } }) );`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); app.use( helmet() );`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); app.use( helmet.contentSecurityPolicy() );`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -78,9 +79,9 @@ describe('S5730', () => { } }) );`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -91,9 +92,9 @@ describe('S5730', () => { } }) );`, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const app = express(); app.use( @@ -103,9 +104,9 @@ describe('S5730', () => { } }) );`, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const app = express(); app.use( @@ -115,11 +116,11 @@ describe('S5730', () => { } }) );`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const csp = require('helmet-csp') const express = require('express'); const app = express(); @@ -128,29 +129,29 @@ describe('S5730', () => { directives: {}, }) );`, - errors: [ - { - message: JSON.stringify({ - message: `Make sure allowing mixed-content is safe here.`, - secondaryLocations: [ - { - column: 12, - line: 7, - endColumn: 26, - endLine: 7, - }, - ], - }), - line: 5, - endLine: 9, - column: 9, - endColumn: 10, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `Make sure allowing mixed-content is safe here.`, + secondaryLocations: [ + { + column: 12, + line: 7, + endColumn: 26, + endLine: 7, + }, + ], + }), + line: 5, + endLine: 9, + column: 9, + endColumn: 10, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const csp = require('helmet-csp') const express = require('express'); const app = express(); @@ -161,10 +162,10 @@ describe('S5730', () => { } }) );`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -173,10 +174,10 @@ describe('S5730', () => { directives: {} }) );`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -187,8 +188,9 @@ describe('S5730', () => { } }) );`, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S5732/unit.test.ts b/packages/jsts/src/rules/S5732/unit.test.ts index a9bdc4fca9..f1181adfef 100644 --- a/packages/jsts/src/rules/S5732/unit.test.ts +++ b/packages/jsts/src/rules/S5732/unit.test.ts @@ -16,26 +16,27 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5732', () => { - const ruleTester = new RuleTester(); - ruleTester.run( - 'Disabling content security policy frame-ancestors directive is security-sensitive', - rule, - { - valid: [ - { - code: ` + it('S5732', () => { + const ruleTester = new RuleTester(); + ruleTester.run( + 'Disabling content security policy frame-ancestors directive is security-sensitive', + rule, + { + valid: [ + { + code: ` const csp = require('helmet-csp') const express = require('express'); const app = express(); app.use( csp({}) // frame-ancestors set to 'self' if no directives are supplied );`, - }, - { - code: ` + }, + { + code: ` const csp = require('helmet-csp') const express = require('express'); const app = express(); @@ -46,9 +47,9 @@ describe('S5732', () => { } }) );`, - }, - { - code: ` + }, + { + code: ` const csp = require('helmet-csp') const express = require('express'); const app = express(); @@ -59,27 +60,27 @@ describe('S5732', () => { } }) );`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); app.use( helmet() );`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); app.use( helmet.contentSecurityPolicy() );`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -90,9 +91,9 @@ describe('S5732', () => { } }) );`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -103,9 +104,9 @@ describe('S5732', () => { } }) );`, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const app = express(); app.use( @@ -115,9 +116,9 @@ describe('S5732', () => { } }) );`, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const app = express(); app.use( @@ -127,11 +128,11 @@ describe('S5732', () => { } }) );`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const csp = require('helmet-csp') const express = require('express'); const app = express(); @@ -140,29 +141,29 @@ describe('S5732', () => { directives: {}, }) );`, - errors: [ - { - message: JSON.stringify({ - message: `Make sure disabling content security policy frame-ancestors directive is safe here.`, - secondaryLocations: [ - { - column: 12, - line: 7, - endColumn: 26, - endLine: 7, - }, - ], - }), - line: 5, - endLine: 9, - column: 9, - endColumn: 10, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `Make sure disabling content security policy frame-ancestors directive is safe here.`, + secondaryLocations: [ + { + column: 12, + line: 7, + endColumn: 26, + endLine: 7, + }, + ], + }), + line: 5, + endLine: 9, + column: 9, + endColumn: 10, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const csp = require('helmet-csp') const express = require('express'); const app = express(); @@ -173,29 +174,29 @@ describe('S5732', () => { }, }) );`, - errors: [ - { - message: JSON.stringify({ - message: `Make sure disabling content security policy frame-ancestors directive is safe here.`, - secondaryLocations: [ - { - column: 14, - line: 8, - endColumn: 40, - endLine: 8, - }, - ], - }), - line: 5, - endLine: 11, - column: 9, - endColumn: 10, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `Make sure disabling content security policy frame-ancestors directive is safe here.`, + secondaryLocations: [ + { + column: 14, + line: 8, + endColumn: 40, + endLine: 8, + }, + ], + }), + line: 5, + endLine: 11, + column: 9, + endColumn: 10, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -204,10 +205,10 @@ describe('S5732', () => { directives: {} }) );`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -218,10 +219,10 @@ describe('S5732', () => { } }) );`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -232,9 +233,10 @@ describe('S5732', () => { } }) );`, - errors: 1, - }, - ], - }, - ); + errors: 1, + }, + ], + }, + ); + }); }); diff --git a/packages/jsts/src/rules/S5734/unit.test.ts b/packages/jsts/src/rules/S5734/unit.test.ts index 9c25a59432..ba643e02f7 100644 --- a/packages/jsts/src/rules/S5734/unit.test.ts +++ b/packages/jsts/src/rules/S5734/unit.test.ts @@ -16,44 +16,45 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5734', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Allowing browsers to sniff MIME types is security-sensitive', rule, { - valid: [ - { - code: ` + it('S5734', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Allowing browsers to sniff MIME types is security-sensitive', rule, { + valid: [ + { + code: ` const express = require('express'); const app = express();`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); app.use( helmet() );`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); const h = helmet(); app.use(h);`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); const h = helmet({ noSniff: true }); app.use(h);`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -62,9 +63,9 @@ describe('S5734', () => { noSniff: true, }) );`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); module.exports = function (app) { app.use( @@ -73,9 +74,9 @@ describe('S5734', () => { }) ); }`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); whatever = function (app) { // Not module.exports app.use( @@ -84,9 +85,9 @@ describe('S5734', () => { }) ); }`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); module.exports = function (foo) { // Not app foo.use( @@ -95,9 +96,9 @@ describe('S5734', () => { }) ); }`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); function foo(app) { // Not exported app.use( @@ -106,9 +107,9 @@ describe('S5734', () => { }) ); }`, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const app = express(); app.use( @@ -116,17 +117,17 @@ describe('S5734', () => { noSniff: false, }) );`, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const app = express(); app.use('/endpoint', callback);`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -135,57 +136,57 @@ describe('S5734', () => { noSniff: false, // Noncompliant }) );`, - errors: [ - { - message: JSON.stringify({ - message: `Make sure allowing browsers to sniff MIME types is safe here.`, - secondaryLocations: [ - { - column: 12, - line: 7, - endColumn: 26, - endLine: 7, - }, - ], - }), - line: 5, - endLine: 9, - column: 9, - endColumn: 10, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `Make sure allowing browsers to sniff MIME types is safe here.`, + secondaryLocations: [ + { + column: 12, + line: 7, + endColumn: 26, + endLine: 7, + }, + ], + }), + line: 5, + endLine: 9, + column: 9, + endColumn: 10, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); const h = helmet({ noSniff: false }); // Noncompliant app.use(h);`, - errors: [ - { - message: JSON.stringify({ - message: `Make sure allowing browsers to sniff MIME types is safe here.`, - secondaryLocations: [ - { - column: 27, - line: 5, - endColumn: 41, - endLine: 5, - }, - ], - }), - line: 6, - endLine: 6, - column: 9, - endColumn: 19, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `Make sure allowing browsers to sniff MIME types is safe here.`, + secondaryLocations: [ + { + column: 27, + line: 5, + endColumn: 41, + endLine: 5, + }, + ], + }), + line: 6, + endLine: 6, + column: 9, + endColumn: 19, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const helmet = require('helmet'); module.exports = function (app) { app.use( @@ -194,29 +195,29 @@ describe('S5734', () => { }) ); }`, - errors: [ - { - message: JSON.stringify({ - message: `Make sure allowing browsers to sniff MIME types is safe here.`, - secondaryLocations: [ - { - column: 14, - line: 6, - endColumn: 28, - endLine: 6, - }, - ], - }), - line: 4, - endLine: 8, - column: 11, - endColumn: 12, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `Make sure allowing browsers to sniff MIME types is safe here.`, + secondaryLocations: [ + { + column: 14, + line: 6, + endColumn: 28, + endLine: 6, + }, + ], + }), + line: 4, + endLine: 8, + column: 11, + endColumn: 12, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const helmet = require('helmet'); module.exports.sensitiveNoSniff = function (app) { app.use( @@ -225,27 +226,28 @@ describe('S5734', () => { }) ); }`, - errors: [ - { - message: JSON.stringify({ - message: `Make sure allowing browsers to sniff MIME types is safe here.`, - secondaryLocations: [ - { - column: 14, - line: 6, - endColumn: 28, - endLine: 6, - }, - ], - }), - line: 4, - endLine: 8, - column: 11, - endColumn: 12, - }, - ], - options: ['sonar-runtime'], - }, - ], + errors: [ + { + message: JSON.stringify({ + message: `Make sure allowing browsers to sniff MIME types is safe here.`, + secondaryLocations: [ + { + column: 14, + line: 6, + endColumn: 28, + endLine: 6, + }, + ], + }), + line: 4, + endLine: 8, + column: 11, + endColumn: 12, + }, + ], + options: ['sonar-runtime'], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S5736/unit.test.ts b/packages/jsts/src/rules/S5736/unit.test.ts index 3fbc02008d..e91684e41f 100644 --- a/packages/jsts/src/rules/S5736/unit.test.ts +++ b/packages/jsts/src/rules/S5736/unit.test.ts @@ -16,23 +16,24 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5736', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Disabling strict HTTP no-referrer policy is security-sensitive', rule, { - valid: [ - { - code: ` + it('S5736', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Disabling strict HTTP no-referrer policy is security-sensitive', rule, { + valid: [ + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); app.use( helmet() );`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -41,18 +42,18 @@ describe('S5736', () => { referrerPolicy: true, }) );`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); app.use( helmet.referrerPolicy() );`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -61,9 +62,9 @@ describe('S5736', () => { policy: 'strict-origin' }) );`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -72,9 +73,9 @@ describe('S5736', () => { policy: ['strict-origin'] }) );`, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const app = express(); app.use( @@ -82,9 +83,9 @@ describe('S5736', () => { referrerPolicy: false, }) );`, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const app = express(); app.use( @@ -92,11 +93,11 @@ describe('S5736', () => { policy: '' }) );`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -105,29 +106,29 @@ describe('S5736', () => { referrerPolicy: false, }) );`, - errors: [ - { - message: JSON.stringify({ - message: `Make sure disabling strict HTTP no-referrer policy is safe here.`, - secondaryLocations: [ - { - column: 12, - line: 7, - endColumn: 33, - endLine: 7, - }, - ], - }), - line: 5, - endLine: 9, - column: 9, - endColumn: 10, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `Make sure disabling strict HTTP no-referrer policy is safe here.`, + secondaryLocations: [ + { + column: 12, + line: 7, + endColumn: 33, + endLine: 7, + }, + ], + }), + line: 5, + endLine: 9, + column: 9, + endColumn: 10, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -136,10 +137,10 @@ describe('S5736', () => { policy: '' }) );`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -148,10 +149,10 @@ describe('S5736', () => { policy: 'unsafe-url' }) );`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -160,10 +161,10 @@ describe('S5736', () => { policy: 'no-referrer-when-downgrade' }) );`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -172,10 +173,10 @@ describe('S5736', () => { policy: ['unsafe-url'] }) );`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -184,8 +185,9 @@ describe('S5736', () => { policy: ['strict-origin', 'unsafe-url'] }) );`, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S5739/unit.test.ts b/packages/jsts/src/rules/S5739/unit.test.ts index df5faf2e46..4d09915f62 100644 --- a/packages/jsts/src/rules/S5739/unit.test.ts +++ b/packages/jsts/src/rules/S5739/unit.test.ts @@ -16,23 +16,24 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5739', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Disabling Strict-Transport-Security policy is security-sensitive', rule, { - valid: [ - { - code: ` + it('S5739', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Disabling Strict-Transport-Security policy is security-sensitive', rule, { + valid: [ + { + code: ` const helmet = require('helmet') const express = require('express'); const app = express(); app.use( helmet() );`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet') const express = require('express'); const app = express(); @@ -41,18 +42,18 @@ describe('S5739', () => { hsts: true, }) );`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet') const express = require('express'); const app = express(); app.use( helmet.hsts({}) );`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet') const express = require('express'); const app = express(); @@ -61,9 +62,9 @@ describe('S5739', () => { maxAge: 31536000, }) );`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet') const express = require('express'); const app = express(); @@ -73,18 +74,18 @@ describe('S5739', () => { includeSubDomains: true, }) );`, - }, - { - code: ` + }, + { + code: ` const hsts = require('hsts'); const express = require('express'); const app = express(); app.use( hsts({}) );`, - }, - { - code: ` + }, + { + code: ` const hsts = require('hsts'); const express = require('express'); const app = express(); @@ -93,9 +94,9 @@ describe('S5739', () => { maxAge: 31536000, }) );`, - }, - { - code: ` + }, + { + code: ` const hsts = require('hsts'); const express = require('express'); const app = express(); @@ -105,9 +106,9 @@ describe('S5739', () => { includeSubDomains: true, }) );`, - }, - { - code: ` + }, + { + code: ` const hsts = require('hsts'); const express = require('express'); const app = express(); @@ -117,9 +118,9 @@ describe('S5739', () => { includeSubDomains: true, }) );`, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const app = express(); app.use( @@ -128,9 +129,9 @@ describe('S5739', () => { includeSubDomains: true, }) );`, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const app = express(); app.use( @@ -139,11 +140,11 @@ describe('S5739', () => { includeSubDomains: true, }) );`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const helmet = require('helmet') const express = require('express'); const app = express(); @@ -152,29 +153,29 @@ describe('S5739', () => { hsts: false, }) );`, - errors: [ - { - message: JSON.stringify({ - message: `Disabling Strict-Transport-Security policy is security-sensitive.`, - secondaryLocations: [ - { - column: 14, - line: 7, - endColumn: 25, - endLine: 7, - }, - ], - }), - line: 5, - endLine: 9, - column: 11, - endColumn: 12, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `Disabling Strict-Transport-Security policy is security-sensitive.`, + secondaryLocations: [ + { + column: 14, + line: 7, + endColumn: 25, + endLine: 7, + }, + ], + }), + line: 5, + endLine: 9, + column: 11, + endColumn: 12, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const helmet = require('helmet') const express = require('express'); const app = express(); @@ -184,46 +185,46 @@ describe('S5739', () => { includeSubDomains: false, }) );`, - errors: [ - { - message: JSON.stringify({ - message: `Disabling Strict-Transport-Security policy is security-sensitive.`, - secondaryLocations: [ - { - column: 14, - line: 7, - endColumn: 29, - endLine: 7, - }, - ], - }), - line: 5, - endLine: 10, - column: 11, - endColumn: 12, - }, - { - message: JSON.stringify({ - message: `Disabling Strict-Transport-Security policy is security-sensitive.`, - secondaryLocations: [ - { - column: 14, - line: 8, - endColumn: 38, - endLine: 8, - }, - ], - }), - line: 5, - endLine: 10, - column: 11, - endColumn: 12, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `Disabling Strict-Transport-Security policy is security-sensitive.`, + secondaryLocations: [ + { + column: 14, + line: 7, + endColumn: 29, + endLine: 7, + }, + ], + }), + line: 5, + endLine: 10, + column: 11, + endColumn: 12, + }, + { + message: JSON.stringify({ + message: `Disabling Strict-Transport-Security policy is security-sensitive.`, + secondaryLocations: [ + { + column: 14, + line: 8, + endColumn: 38, + endLine: 8, + }, + ], + }), + line: 5, + endLine: 10, + column: 11, + endColumn: 12, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const hsts = require('hsts'); const express = require('express'); const app = express(); @@ -233,8 +234,9 @@ describe('S5739', () => { includeSubDomains: false, }) );`, - errors: 2, - }, - ], + errors: 2, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S5742/unit.test.ts b/packages/jsts/src/rules/S5742/unit.test.ts index 275a3bfde3..71e6b6f12a 100644 --- a/packages/jsts/src/rules/S5742/unit.test.ts +++ b/packages/jsts/src/rules/S5742/unit.test.ts @@ -16,44 +16,45 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5742', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Disabling Certificate Transparency monitoring is security-sensitive', rule, { - valid: [ - { - code: ` + it('S5742', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Disabling Certificate Transparency monitoring is security-sensitive', rule, { + valid: [ + { + code: ` const express = require('express'); const app = express();`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); app.use( helmet() );`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); const h = helmet(); app.use(h);`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); const h = helmet({ expectCt: true }); app.use(h);`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -62,9 +63,9 @@ describe('S5742', () => { expectCt: true, }) );`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); module.exports = function (app) { app.use( @@ -73,9 +74,9 @@ describe('S5742', () => { }) ); }`, - }, - { - code: ` + }, + { + code: ` const helmet = require('helmet'); module.exports = function (foo) { app.use( @@ -84,9 +85,9 @@ describe('S5742', () => { }) ); }`, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const app = express(); app.use( @@ -94,17 +95,17 @@ describe('S5742', () => { expectCt: false, }) );`, - }, - { - code: ` + }, + { + code: ` const express = require('express'); const app = express(); app.use('/endpoint', callback);`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); @@ -113,57 +114,57 @@ describe('S5742', () => { expectCt: false, // Noncompliant }) );`, - errors: [ - { - message: JSON.stringify({ - message: `Make sure disabling Certificate Transparency monitoring is safe here.`, - secondaryLocations: [ - { - column: 12, - line: 7, - endColumn: 27, - endLine: 7, - }, - ], - }), - line: 5, - endLine: 9, - column: 9, - endColumn: 10, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `Make sure disabling Certificate Transparency monitoring is safe here.`, + secondaryLocations: [ + { + column: 12, + line: 7, + endColumn: 27, + endLine: 7, + }, + ], + }), + line: 5, + endLine: 9, + column: 9, + endColumn: 10, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const helmet = require('helmet'); const express = require('express'); const app = express(); const h = helmet({ expectCt: false }); // Noncompliant app.use(h);`, - errors: [ - { - message: JSON.stringify({ - message: `Make sure disabling Certificate Transparency monitoring is safe here.`, - secondaryLocations: [ - { - column: 27, - line: 5, - endColumn: 42, - endLine: 5, - }, - ], - }), - line: 6, - endLine: 6, - column: 9, - endColumn: 19, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `Make sure disabling Certificate Transparency monitoring is safe here.`, + secondaryLocations: [ + { + column: 27, + line: 5, + endColumn: 42, + endLine: 5, + }, + ], + }), + line: 6, + endLine: 6, + column: 9, + endColumn: 19, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const helmet = require('helmet'); module.exports = function (app) { app.use( @@ -172,29 +173,29 @@ describe('S5742', () => { }) ); }`, - errors: [ - { - message: JSON.stringify({ - message: `Make sure disabling Certificate Transparency monitoring is safe here.`, - secondaryLocations: [ - { - column: 14, - line: 6, - endColumn: 29, - endLine: 6, - }, - ], - }), - line: 4, - endLine: 8, - column: 11, - endColumn: 12, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `Make sure disabling Certificate Transparency monitoring is safe here.`, + secondaryLocations: [ + { + column: 14, + line: 6, + endColumn: 29, + endLine: 6, + }, + ], + }), + line: 4, + endLine: 8, + column: 11, + endColumn: 12, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const helmet = require('helmet'); module.exports.sensitiveExpectCt = function (app) { app.use( @@ -203,27 +204,28 @@ describe('S5742', () => { }) ); }`, - errors: [ - { - message: JSON.stringify({ - message: `Make sure disabling Certificate Transparency monitoring is safe here.`, - secondaryLocations: [ - { - column: 14, - line: 6, - endColumn: 29, - endLine: 6, - }, - ], - }), - line: 4, - endLine: 8, - column: 11, - endColumn: 12, - }, - ], - options: ['sonar-runtime'], - }, - ], + errors: [ + { + message: JSON.stringify({ + message: `Make sure disabling Certificate Transparency monitoring is safe here.`, + secondaryLocations: [ + { + column: 14, + line: 6, + endColumn: 29, + endLine: 6, + }, + ], + }), + line: 4, + endLine: 8, + column: 11, + endColumn: 12, + }, + ], + options: ['sonar-runtime'], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S5743/unit.test.ts b/packages/jsts/src/rules/S5743/unit.test.ts index 4d0d5cd9a4..d36136a910 100644 --- a/packages/jsts/src/rules/S5743/unit.test.ts +++ b/packages/jsts/src/rules/S5743/unit.test.ts @@ -16,15 +16,16 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5743', () => { - const ruleTester = new RuleTester(); + it('S5743', () => { + const ruleTester = new RuleTester(); - ruleTester.run('Allowing browsers to perform DNS prefetching is security-sensitive', rule, { - valid: [ - { - code: ` + ruleTester.run('Allowing browsers to perform DNS prefetching is security-sensitive', rule, { + valid: [ + { + code: ` const dnsPrefetchControl = require('dns-prefetch-control') const helmet = require('helmet') @@ -32,9 +33,9 @@ describe('S5743', () => { app.use(dnsPrefetchControl({ allow: false })) // Compliant }; `, - }, - { - code: ` + }, + { + code: ` const dnsPrefetchControl = require('dns-prefetch-control') const helmet = require('helmet') module.exports.compliantDnsPrefetch = function(app) { @@ -43,27 +44,27 @@ describe('S5743', () => { ); }; `, - }, - { - code: ` + }, + { + code: ` const dnsPrefetchControl = require('dns-prefetch-control') const helmet = require('helmet') module.exports.compliantDnsPrefetch = function(app) { app.use(dnsPrefetchControl()) // Compliant by default }; `, - }, - { - code: ` + }, + { + code: ` const dnsPrefetchControl = require('dns-prefetch-control') const helmet = require('helmet') module.exports.compliantDnsPrefetch = function(app) { app.use(helmet.dnsPrefetchControl()) // Compliant by default }; `, - }, - { - code: ` + }, + { + code: ` const dnsPrefetchControl = require('dns-prefetch-control'); const helmet = require('helmet'); module.exports.sensitiveDnsPrefetch = function(app) { @@ -74,33 +75,33 @@ describe('S5743', () => { app.use(dnsPrefetchControl(options)); }; `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const dnsPrefetchControl = require('dns-prefetch-control') const helmet = require('helmet') module.exports.sensitiveDnsPrefetch = function(app) { app.use(dnsPrefetchControl({ allow: true })) // Sensitive }; `, - errors: [ - { - line: 5, - endLine: 5, - column: 17, - endColumn: 35, - message: JSON.stringify({ - message: 'Make sure allowing browsers to perform DNS prefetching is safe here.', - secondaryLocations: [{ column: 37, line: 5, endColumn: 48, endLine: 5 }], - }), - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + line: 5, + endLine: 5, + column: 17, + endColumn: 35, + message: JSON.stringify({ + message: 'Make sure allowing browsers to perform DNS prefetching is safe here.', + secondaryLocations: [{ column: 37, line: 5, endColumn: 48, endLine: 5 }], + }), + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const dnsPrefetchControl = require('dns-prefetch-control') const helmet = require('helmet') module.exports.sensitiveDnsPrefetch = function(app) { @@ -111,22 +112,22 @@ describe('S5743', () => { ); }; `, - errors: [ - { - line: 6, - endLine: 6, - column: 11, - endColumn: 36, - message: JSON.stringify({ - message: 'Make sure allowing browsers to perform DNS prefetching is safe here.', - secondaryLocations: [{ column: 12, line: 7, endColumn: 23, endLine: 7 }], - }), - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + line: 6, + endLine: 6, + column: 11, + endColumn: 36, + message: JSON.stringify({ + message: 'Make sure allowing browsers to perform DNS prefetching is safe here.', + secondaryLocations: [{ column: 12, line: 7, endColumn: 23, endLine: 7 }], + }), + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const dnsPrefetchControl = require('dns-prefetch-control') const helmet = require('helmet') module.exports.sensitiveDnsPrefetch = function(app) { @@ -137,20 +138,21 @@ describe('S5743', () => { ); }; `, - errors: [ - { - line: 6, - endLine: 6, - column: 11, - endColumn: 17, - message: JSON.stringify({ - message: 'Make sure allowing browsers to perform DNS prefetching is safe here.', - secondaryLocations: [{ column: 12, line: 7, endColumn: 37, endLine: 7 }], - }), - }, - ], - options: ['sonar-runtime'], - }, - ], + errors: [ + { + line: 6, + endLine: 6, + column: 11, + endColumn: 17, + message: JSON.stringify({ + message: 'Make sure allowing browsers to perform DNS prefetching is safe here.', + secondaryLocations: [{ column: 12, line: 7, endColumn: 37, endLine: 7 }], + }), + }, + ], + options: ['sonar-runtime'], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S5757/unit.test.ts b/packages/jsts/src/rules/S5757/unit.test.ts index b6355913fe..2a9512db2b 100644 --- a/packages/jsts/src/rules/S5757/unit.test.ts +++ b/packages/jsts/src/rules/S5757/unit.test.ts @@ -16,33 +16,34 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5757', () => { - const ruleTester = new RuleTester(); + it('S5757', () => { + const ruleTester = new RuleTester(); - ruleTester.run('Allowing confidential information to be logged is security-sensitive', rule, { - valid: [ - { - code: ` + ruleTester.run('Allowing confidential information to be logged is security-sensitive', rule, { + valid: [ + { + code: ` const { Signale } = require('signale'); const options = { secrets: ["([0-9]{4}-?)+"] }; const logger = new Signale(options); // Compliant `, - }, - { - code: ` + }, + { + code: ` const signale = require('signale'); const options = { secrets: [] }; const logger = new signale.Other(options); `, - }, - { - code: ` + }, + { + code: ` const { Signale } = require('signale'); let options = { secrets: [] @@ -52,18 +53,18 @@ describe('S5757', () => { } const logger = new Signale(options); `, - }, - { - code: ` + }, + { + code: ` const { Signale } = require('signale'); let options = { secrets: getSecrets() }; const logger = new Signale(options); `, - }, - { - code: ` + }, + { + code: ` const signale = require('signale'); let secretsArray = []; if (x) { @@ -74,109 +75,110 @@ describe('S5757', () => { }; const logger = new signale.Signale(options); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const signale = require('signale'); const options = { secrets: [] }; const logger = new signale.Signale(options); // Sensitive `, - errors: [ - { - line: 6, - endLine: 6, - column: 26, - endColumn: 41, - message: JSON.stringify({ - message: 'Make sure confidential information is not logged here.', - secondaryLocations: [{ column: 8, line: 4, endColumn: 19, endLine: 4 }], - }), - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + line: 6, + endLine: 6, + column: 26, + endColumn: 41, + message: JSON.stringify({ + message: 'Make sure confidential information is not logged here.', + secondaryLocations: [{ column: 8, line: 4, endColumn: 19, endLine: 4 }], + }), + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const { Signale } = require('signale'); const options = { secrets: [] }; const logger = new Signale(options); // Sensitive `, - errors: [ - { - line: 6, - endLine: 6, - column: 26, - endColumn: 33, - message: JSON.stringify({ - message: 'Make sure confidential information is not logged here.', - secondaryLocations: [{ column: 8, line: 4, endColumn: 19, endLine: 4 }], - }), - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + line: 6, + endLine: 6, + column: 26, + endColumn: 33, + message: JSON.stringify({ + message: 'Make sure confidential information is not logged here.', + secondaryLocations: [{ column: 8, line: 4, endColumn: 19, endLine: 4 }], + }), + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const { Signale } = require('signale'); const options = { other: [] }; const logger = new Signale(options); // Sensitive `, - errors: [ - { - line: 6, - endLine: 6, - column: 26, - endColumn: 33, - message: JSON.stringify({ - message: 'Make sure confidential information is not logged here.', - secondaryLocations: [{ column: 22, line: 3, endColumn: 7, endLine: 5 }], - }), - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + line: 6, + endLine: 6, + column: 26, + endColumn: 33, + message: JSON.stringify({ + message: 'Make sure confidential information is not logged here.', + secondaryLocations: [{ column: 22, line: 3, endColumn: 7, endLine: 5 }], + }), + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const signale = require('signale'); const logger = new signale.Signale(); // Sensitive `, - errors: [ - { - line: 3, - endLine: 3, - column: 26, - endColumn: 41, - message: JSON.stringify({ - message: 'Make sure confidential information is not logged here.', - secondaryLocations: [], - }), - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + line: 3, + endLine: 3, + column: 26, + endColumn: 41, + message: JSON.stringify({ + message: 'Make sure confidential information is not logged here.', + secondaryLocations: [], + }), + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const {Signale} = require('signale'); const logger = new Signale(); // Sensitive `, - errors: [ - { - message: JSON.stringify({ - message: 'Make sure confidential information is not logged here.', - secondaryLocations: [], - }), - }, - ], - options: ['sonar-runtime'], - }, - ], + errors: [ + { + message: JSON.stringify({ + message: 'Make sure confidential information is not logged here.', + secondaryLocations: [], + }), + }, + ], + options: ['sonar-runtime'], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S5759/unit.test.ts b/packages/jsts/src/rules/S5759/unit.test.ts index 11aac175d8..5c431b91d5 100644 --- a/packages/jsts/src/rules/S5759/unit.test.ts +++ b/packages/jsts/src/rules/S5759/unit.test.ts @@ -16,74 +16,76 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5759', () => { - const ruleTester = new RuleTester(); + it('S5759', () => { + const ruleTester = new RuleTester(); - ruleTester.run('ip forwarding should be avoided', rule, { - valid: [ - { - code: ` + ruleTester.run('ip forwarding should be avoided', rule, { + valid: [ + { + code: ` const httpProxy = require('http-proxy') httpProxy.createProxyServer({target: 'http://localhost:9000'})`, - }, - { - code: ` + }, + { + code: ` const httpProxy = require('http-proxy') httpProxy.other({target: 'http://localhost:9000'})`, - }, - { - code: ` + }, + { + code: ` const httpProxy = require('http-proxy') httpProxy.createProxyServer()`, - }, - { - code: ` + }, + { + code: ` const { createProxyServer } = require('other') createProxyServer({xfwd: true})`, - }, - { - code: ` + }, + { + code: ` const { createProxyMiddleware } = require('http-proxy-middleware'); createProxyMiddleware({ target: 'http://localhost:9000', changeOrigin: true});`, - }, - { - code: ` + }, + { + code: ` createProxyServer({xfwd: true}); createProxyMiddleware({ target: 'http://localhost:9000', changeOrigin: true, xfwd: true });`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const httpProxy = require('http-proxy') httpProxy.createProxyServer({target: 'http://localhost:9000', xfwd: true})`, - errors: [ - { - message: JSON.stringify({ - message: 'Make sure forwarding client IP address is safe here.', - secondaryLocations: [{ column: 68, line: 3, endColumn: 78, endLine: 3 }], - }), - line: 3, - column: 7, - endColumn: 34, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: 'Make sure forwarding client IP address is safe here.', + secondaryLocations: [{ column: 68, line: 3, endColumn: 78, endLine: 3 }], + }), + line: 3, + column: 7, + endColumn: 34, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const { createProxyServer } = require('http-proxy') createProxyServer({target: 'http://localhost:9000', xfwd: true})`, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const { createProxyMiddleware } = require('http-proxy-middleware'); createProxyMiddleware({ target: 'http://localhost:9000', changeOrigin: true, xfwd: true });`, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S5842/unit.test.ts b/packages/jsts/src/rules/S5842/unit.test.ts index 6f28dea33a..86e8c35ae0 100644 --- a/packages/jsts/src/rules/S5842/unit.test.ts +++ b/packages/jsts/src/rules/S5842/unit.test.ts @@ -16,154 +16,156 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5842', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Regular expression repetitions matching the empty string', rule, { - valid: [ - { - code: `/x*|/`, - }, - { - code: `/x*/`, - }, - { - code: `/x?/`, - }, - { - code: `/(?:x|y)*/`, - }, - { - code: `/(?:x+)+/`, - }, - { - code: `/(?:x+)*/`, - }, - { - code: `/(?:x+)?/`, - }, - { - code: `/((x+))*/`, - }, - ], - invalid: [ - { - code: `/(?:)*/`, - errors: 1, - }, - { - code: `/(?:)?/`, - errors: 1, - }, - { - code: `/(?:)+/`, - errors: 1, - }, - { - code: `/()*/`, - errors: 1, - }, - { - code: `/()?/`, - errors: 1, - }, - { - code: `/()+/`, - errors: 1, - }, - { - code: `/xyz|(?:)*/`, - errors: 1, - }, - { - code: `/(?:|x)*/`, - errors: 1, - }, - { - code: `/(?:x|)*/`, - errors: 1, - }, - { - code: `/(?:x|y*)*"/`, - errors: 1, - }, - { - code: `/(?:x*|y*)*/`, - errors: 1, - }, - { - code: `/(?:x?|y*)*/`, - errors: 1, - }, - { - code: `/(?:x*)*/`, - errors: 1, - }, - { - code: `/(?:x?)*/`, - errors: 1, - }, - { - code: `/(?:x*)?/`, - errors: 1, - }, - { - code: `/(?:x?)?/`, - errors: 1, - }, - { - code: `/(?:x*)+/`, - errors: 1, - }, - { - code: `/(?:x?)+/`, - errors: 1, - }, - { - code: `/(x*)*/`, - errors: 1, - }, - { - code: `/((x*))*/`, - errors: 1, - }, - { - code: `/(?:x*y*)*/`, - errors: 1, - }, - { - code: `/(?:())*"/`, - errors: 1, - }, - { - code: `/(?:(?:))*/`, - errors: 1, - }, - { - code: `/(())*/`, - errors: 1, - }, - { - code: `/(()x*)*/`, - errors: 1, - }, - { - code: `/(()|x)*/`, - errors: 1, - }, - { - code: `/($)*/`, - errors: 1, - }, - { - code: `/(\\b)*/`, - errors: 1, - }, - { - code: `/((?!x))*/`, - errors: 1, - }, - ], + it('S5842', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Regular expression repetitions matching the empty string', rule, { + valid: [ + { + code: `/x*|/`, + }, + { + code: `/x*/`, + }, + { + code: `/x?/`, + }, + { + code: `/(?:x|y)*/`, + }, + { + code: `/(?:x+)+/`, + }, + { + code: `/(?:x+)*/`, + }, + { + code: `/(?:x+)?/`, + }, + { + code: `/((x+))*/`, + }, + ], + invalid: [ + { + code: `/(?:)*/`, + errors: 1, + }, + { + code: `/(?:)?/`, + errors: 1, + }, + { + code: `/(?:)+/`, + errors: 1, + }, + { + code: `/()*/`, + errors: 1, + }, + { + code: `/()?/`, + errors: 1, + }, + { + code: `/()+/`, + errors: 1, + }, + { + code: `/xyz|(?:)*/`, + errors: 1, + }, + { + code: `/(?:|x)*/`, + errors: 1, + }, + { + code: `/(?:x|)*/`, + errors: 1, + }, + { + code: `/(?:x|y*)*"/`, + errors: 1, + }, + { + code: `/(?:x*|y*)*/`, + errors: 1, + }, + { + code: `/(?:x?|y*)*/`, + errors: 1, + }, + { + code: `/(?:x*)*/`, + errors: 1, + }, + { + code: `/(?:x?)*/`, + errors: 1, + }, + { + code: `/(?:x*)?/`, + errors: 1, + }, + { + code: `/(?:x?)?/`, + errors: 1, + }, + { + code: `/(?:x*)+/`, + errors: 1, + }, + { + code: `/(?:x?)+/`, + errors: 1, + }, + { + code: `/(x*)*/`, + errors: 1, + }, + { + code: `/((x*))*/`, + errors: 1, + }, + { + code: `/(?:x*y*)*/`, + errors: 1, + }, + { + code: `/(?:())*"/`, + errors: 1, + }, + { + code: `/(?:(?:))*/`, + errors: 1, + }, + { + code: `/(())*/`, + errors: 1, + }, + { + code: `/(()x*)*/`, + errors: 1, + }, + { + code: `/(()|x)*/`, + errors: 1, + }, + { + code: `/($)*/`, + errors: 1, + }, + { + code: `/(\\b)*/`, + errors: 1, + }, + { + code: `/((?!x))*/`, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S5843/unit.test.ts b/packages/jsts/src/rules/S5843/unit.test.ts index 62c50bb2f3..42e39f37f0 100644 --- a/packages/jsts/src/rules/S5843/unit.test.ts +++ b/packages/jsts/src/rules/S5843/unit.test.ts @@ -16,544 +16,546 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5843', () => { - const createOptions = (threshold: number) => { - return [{ threshold }, 'sonar-runtime']; - }; + it('S5843', () => { + const createOptions = (threshold: number) => { + return [{ threshold }, 'sonar-runtime']; + }; - const ruleTesterThreshold0 = new RuleTester(); - ruleTesterThreshold0.run( - 'Regular expressions should not be too complicated with threshold 0', - rule, - { - valid: [ - { - code: `let regex; + const ruleTesterThreshold0 = new RuleTester(); + ruleTesterThreshold0.run( + 'Regular expressions should not be too complicated with threshold 0', + rule, + { + valid: [ + { + code: `let regex; if (isString(regex)) { regex = new RegExp('^' + regex + '$'); }`, - }, - { - code: `/ /`, - options: createOptions(0), - }, - { - code: `/abc/`, - options: createOptions(0), - }, - { - code: `/^abc$/`, - options: createOptions(0), - }, - { - code: `/(?:abc)/`, - options: createOptions(0), - }, - { - code: `/(abc)/`, - options: createOptions(0), - }, - { - code: `/\\w.u/`, - options: createOptions(0), - }, - { - code: `RegExp('abc')`, - options: createOptions(0), - }, - { - code: `new RegExp('abc')`, - options: createOptions(0), - }, - { - code: 'RegExp(`abc`)', - options: createOptions(0), - }, - { - code: `RegExp('[malformed')`, - options: createOptions(0), - }, - { - code: `RegExp(123)`, - options: createOptions(0), - }, - { - code: `RegExp(unknown)`, - options: createOptions(0), - }, - { - code: `let uninitialized; RegExp(uninitialized)`, - options: createOptions(0), - }, - { - code: `new Foo('abc')`, - options: createOptions(0), - }, - { - code: `Foo('abc')`, - options: createOptions(0), - }, - { - code: `RegExp('(a|' + 'b)')`, - options: createOptions(0), - }, - ], - invalid: [ - { - code: `/(?=abc)/`, - errors: [ - { - message: JSON.stringify({ - message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, - secondaryLocations: [ - { message: `+1`, column: 1, line: 1, endColumn: 4, endLine: 1 }, - ], - cost: 1, - }), - line: 1, - endLine: 1, - column: 1, - endColumn: 10, - }, - ], - options: createOptions(0), - }, - { - code: `RegExp('\\r?');`, - errors: [ - { - message: JSON.stringify({ - message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, - secondaryLocations: [], // Secondary location removed when invalid (start===end) - cost: 1, - }), - line: 1, - endLine: 1, - column: 8, - endColumn: 13, - }, - ], - options: createOptions(0), - }, - { - code: `RegExp('\\\\r?');`, - errors: [ - { - message: JSON.stringify({ - message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, - secondaryLocations: [ - { message: '+1', column: 11, line: 1, endColumn: 12, endLine: 1 }, - ], - cost: 1, - }), - line: 1, - endLine: 1, - column: 8, - endColumn: 14, - }, - ], - options: createOptions(0), - }, - { - code: `/(?<=abc)/`, - errors: [ - { - message: JSON.stringify({ - message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, - secondaryLocations: [ - { message: `+1`, column: 1, line: 1, endColumn: 5, endLine: 1 }, - ], - cost: 1, - }), - line: 1, - endLine: 1, - column: 1, - endColumn: 11, - }, - ], - options: createOptions(0), - }, - { - code: `/[a-z0-9]/`, - errors: [ - { - message: JSON.stringify({ - message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, - secondaryLocations: [ - { message: `+1`, column: 1, line: 1, endColumn: 2, endLine: 1 }, - ], - cost: 1, - }), - line: 1, - endLine: 1, - column: 1, - endColumn: 11, - }, - ], - options: createOptions(0), - }, - { - code: `/x*/`, - errors: [ - { - message: JSON.stringify({ - message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, - secondaryLocations: [ - { message: `+1`, column: 2, line: 1, endColumn: 3, endLine: 1 }, - ], - cost: 1, - }), - line: 1, - endLine: 1, - column: 1, - endColumn: 5, - }, - ], - options: createOptions(0), - }, - { - code: `/x{1,2}/`, - errors: [ - { - message: JSON.stringify({ - message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, - secondaryLocations: [ - { message: `+1`, column: 2, line: 1, endColumn: 7, endLine: 1 }, - ], - cost: 1, - }), - line: 1, - endLine: 1, - column: 1, - endColumn: 9, - }, - ], - options: createOptions(0), - }, - { - code: `/(?:abc)*/`, - errors: 1, - options: createOptions(0), - }, - { - code: `/((?:abc)*)/`, - errors: 1, - options: createOptions(0), - }, - { - code: `/((?:abc)*)?/`, - errors: 1, - options: createOptions(0), - }, - { - code: `/a|b/`, - errors: [ - { - message: JSON.stringify({ - message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, - secondaryLocations: [ - { message: `+1`, column: 2, line: 1, endColumn: 3, endLine: 1 }, - ], - cost: 1, - }), - line: 1, - endLine: 1, - column: 1, - endColumn: 6, - }, - ], - options: createOptions(0), - }, - { - code: `/a|b|c/`, - errors: [ - { - message: JSON.stringify({ - message: `Simplify this regular expression to reduce its complexity from 2 to the 0 allowed.`, - secondaryLocations: [ - { message: `+1`, column: 2, line: 1, endColumn: 3, endLine: 1 }, - { message: `+1`, column: 4, line: 1, endColumn: 5, endLine: 1 }, - ], - cost: 2, - }), - line: 1, - endLine: 1, - column: 1, - endColumn: 8, - }, - ], - options: createOptions(0), - }, - { - code: `/(?:a|b)*/`, - errors: 1, - options: createOptions(0), - }, - { - code: `/(?:a|b|c)*/`, - errors: [ - { - message: JSON.stringify({ - message: `Simplify this regular expression to reduce its complexity from 4 to the 0 allowed.`, - secondaryLocations: [ - { message: `+1`, column: 10, line: 1, endColumn: 11, endLine: 1 }, - { - message: `+2 (incl 1 for nesting)`, - column: 5, - line: 1, - endColumn: 6, - endLine: 1, - }, - { message: `+1`, column: 7, line: 1, endColumn: 8, endLine: 1 }, - ], - cost: 4, - }), - line: 1, - endLine: 1, - column: 1, - endColumn: 13, - }, - ], - options: createOptions(0), - }, - { - code: `/(foo)\\1/`, - errors: [ - { - message: JSON.stringify({ - message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, - secondaryLocations: [ - { message: `+1`, column: 6, line: 1, endColumn: 8, endLine: 1 }, - ], - cost: 1, - }), - line: 1, - endLine: 1, - column: 1, - endColumn: 10, - }, - ], - options: createOptions(0), - }, - { - code: `RegExp('x*')`, - errors: [ - { - message: JSON.stringify({ - message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, - secondaryLocations: [ - { message: `+1`, column: 9, line: 1, endColumn: 10, endLine: 1 }, - ], - cost: 1, - }), - line: 1, - endLine: 1, - column: 8, - endColumn: 12, - }, - ], - options: createOptions(0), - }, - { - code: `new RegExp('x*')`, - errors: [ - { - message: JSON.stringify({ - message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, - secondaryLocations: [ - { message: `+1`, column: 13, line: 1, endColumn: 14, endLine: 1 }, - ], - cost: 1, - }), - line: 1, - endLine: 1, - column: 12, - endColumn: 16, - }, - ], - options: createOptions(0), - }, - { - code: 'RegExp(`x*`)', - errors: 1, - options: createOptions(0), - }, - { - code: ` + }, + { + code: `/ /`, + options: createOptions(0), + }, + { + code: `/abc/`, + options: createOptions(0), + }, + { + code: `/^abc$/`, + options: createOptions(0), + }, + { + code: `/(?:abc)/`, + options: createOptions(0), + }, + { + code: `/(abc)/`, + options: createOptions(0), + }, + { + code: `/\\w.u/`, + options: createOptions(0), + }, + { + code: `RegExp('abc')`, + options: createOptions(0), + }, + { + code: `new RegExp('abc')`, + options: createOptions(0), + }, + { + code: 'RegExp(`abc`)', + options: createOptions(0), + }, + { + code: `RegExp('[malformed')`, + options: createOptions(0), + }, + { + code: `RegExp(123)`, + options: createOptions(0), + }, + { + code: `RegExp(unknown)`, + options: createOptions(0), + }, + { + code: `let uninitialized; RegExp(uninitialized)`, + options: createOptions(0), + }, + { + code: `new Foo('abc')`, + options: createOptions(0), + }, + { + code: `Foo('abc')`, + options: createOptions(0), + }, + { + code: `RegExp('(a|' + 'b)')`, + options: createOptions(0), + }, + ], + invalid: [ + { + code: `/(?=abc)/`, + errors: [ + { + message: JSON.stringify({ + message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, + secondaryLocations: [ + { message: `+1`, column: 1, line: 1, endColumn: 4, endLine: 1 }, + ], + cost: 1, + }), + line: 1, + endLine: 1, + column: 1, + endColumn: 10, + }, + ], + options: createOptions(0), + }, + { + code: `RegExp('\\r?');`, + errors: [ + { + message: JSON.stringify({ + message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, + secondaryLocations: [], // Secondary location removed when invalid (start===end) + cost: 1, + }), + line: 1, + endLine: 1, + column: 8, + endColumn: 13, + }, + ], + options: createOptions(0), + }, + { + code: `RegExp('\\\\r?');`, + errors: [ + { + message: JSON.stringify({ + message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, + secondaryLocations: [ + { message: '+1', column: 11, line: 1, endColumn: 12, endLine: 1 }, + ], + cost: 1, + }), + line: 1, + endLine: 1, + column: 8, + endColumn: 14, + }, + ], + options: createOptions(0), + }, + { + code: `/(?<=abc)/`, + errors: [ + { + message: JSON.stringify({ + message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, + secondaryLocations: [ + { message: `+1`, column: 1, line: 1, endColumn: 5, endLine: 1 }, + ], + cost: 1, + }), + line: 1, + endLine: 1, + column: 1, + endColumn: 11, + }, + ], + options: createOptions(0), + }, + { + code: `/[a-z0-9]/`, + errors: [ + { + message: JSON.stringify({ + message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, + secondaryLocations: [ + { message: `+1`, column: 1, line: 1, endColumn: 2, endLine: 1 }, + ], + cost: 1, + }), + line: 1, + endLine: 1, + column: 1, + endColumn: 11, + }, + ], + options: createOptions(0), + }, + { + code: `/x*/`, + errors: [ + { + message: JSON.stringify({ + message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, + secondaryLocations: [ + { message: `+1`, column: 2, line: 1, endColumn: 3, endLine: 1 }, + ], + cost: 1, + }), + line: 1, + endLine: 1, + column: 1, + endColumn: 5, + }, + ], + options: createOptions(0), + }, + { + code: `/x{1,2}/`, + errors: [ + { + message: JSON.stringify({ + message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, + secondaryLocations: [ + { message: `+1`, column: 2, line: 1, endColumn: 7, endLine: 1 }, + ], + cost: 1, + }), + line: 1, + endLine: 1, + column: 1, + endColumn: 9, + }, + ], + options: createOptions(0), + }, + { + code: `/(?:abc)*/`, + errors: 1, + options: createOptions(0), + }, + { + code: `/((?:abc)*)/`, + errors: 1, + options: createOptions(0), + }, + { + code: `/((?:abc)*)?/`, + errors: 1, + options: createOptions(0), + }, + { + code: `/a|b/`, + errors: [ + { + message: JSON.stringify({ + message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, + secondaryLocations: [ + { message: `+1`, column: 2, line: 1, endColumn: 3, endLine: 1 }, + ], + cost: 1, + }), + line: 1, + endLine: 1, + column: 1, + endColumn: 6, + }, + ], + options: createOptions(0), + }, + { + code: `/a|b|c/`, + errors: [ + { + message: JSON.stringify({ + message: `Simplify this regular expression to reduce its complexity from 2 to the 0 allowed.`, + secondaryLocations: [ + { message: `+1`, column: 2, line: 1, endColumn: 3, endLine: 1 }, + { message: `+1`, column: 4, line: 1, endColumn: 5, endLine: 1 }, + ], + cost: 2, + }), + line: 1, + endLine: 1, + column: 1, + endColumn: 8, + }, + ], + options: createOptions(0), + }, + { + code: `/(?:a|b)*/`, + errors: 1, + options: createOptions(0), + }, + { + code: `/(?:a|b|c)*/`, + errors: [ + { + message: JSON.stringify({ + message: `Simplify this regular expression to reduce its complexity from 4 to the 0 allowed.`, + secondaryLocations: [ + { message: `+1`, column: 10, line: 1, endColumn: 11, endLine: 1 }, + { + message: `+2 (incl 1 for nesting)`, + column: 5, + line: 1, + endColumn: 6, + endLine: 1, + }, + { message: `+1`, column: 7, line: 1, endColumn: 8, endLine: 1 }, + ], + cost: 4, + }), + line: 1, + endLine: 1, + column: 1, + endColumn: 13, + }, + ], + options: createOptions(0), + }, + { + code: `/(foo)\\1/`, + errors: [ + { + message: JSON.stringify({ + message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, + secondaryLocations: [ + { message: `+1`, column: 6, line: 1, endColumn: 8, endLine: 1 }, + ], + cost: 1, + }), + line: 1, + endLine: 1, + column: 1, + endColumn: 10, + }, + ], + options: createOptions(0), + }, + { + code: `RegExp('x*')`, + errors: [ + { + message: JSON.stringify({ + message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, + secondaryLocations: [ + { message: `+1`, column: 9, line: 1, endColumn: 10, endLine: 1 }, + ], + cost: 1, + }), + line: 1, + endLine: 1, + column: 8, + endColumn: 12, + }, + ], + options: createOptions(0), + }, + { + code: `new RegExp('x*')`, + errors: [ + { + message: JSON.stringify({ + message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, + secondaryLocations: [ + { message: `+1`, column: 13, line: 1, endColumn: 14, endLine: 1 }, + ], + cost: 1, + }), + line: 1, + endLine: 1, + column: 12, + endColumn: 16, + }, + ], + options: createOptions(0), + }, + { + code: 'RegExp(`x*`)', + errors: 1, + options: createOptions(0), + }, + { + code: ` RegExp('/s*') `, - options: createOptions(0), - errors: [ - { - message: JSON.stringify({ - message: - 'Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.', - secondaryLocations: [ - { - message: '+1', - column: 18, - line: 2, - endColumn: 19, - endLine: 2, - }, - ], - cost: 1, - }), - }, - ], - }, - { - code: ` + options: createOptions(0), + errors: [ + { + message: JSON.stringify({ + message: + 'Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.', + secondaryLocations: [ + { + message: '+1', + column: 18, + line: 2, + endColumn: 19, + endLine: 2, + }, + ], + cost: 1, + }), + }, + ], + }, + { + code: ` RegExp('|/?[a-z]') `, - options: createOptions(0), - errors: [ - { - message: JSON.stringify({ - message: - 'Simplify this regular expression to reduce its complexity from 4 to the 0 allowed.', - secondaryLocations: [ - { message: '+1', column: 16, line: 2, endColumn: 17, endLine: 2 }, - { - message: '+2 (incl 1 for nesting)', - column: 18, - line: 2, - endColumn: 19, - endLine: 2, - }, - { message: '+1', column: 19, line: 2, endColumn: 20, endLine: 2 }, - ], - cost: 4, - }), - }, - ], - }, - ], - }, - ); + options: createOptions(0), + errors: [ + { + message: JSON.stringify({ + message: + 'Simplify this regular expression to reduce its complexity from 4 to the 0 allowed.', + secondaryLocations: [ + { message: '+1', column: 16, line: 2, endColumn: 17, endLine: 2 }, + { + message: '+2 (incl 1 for nesting)', + column: 18, + line: 2, + endColumn: 19, + endLine: 2, + }, + { message: '+1', column: 19, line: 2, endColumn: 20, endLine: 2 }, + ], + cost: 4, + }), + }, + ], + }, + ], + }, + ); - const ruleTesterThreshold1 = new RuleTester(); - ruleTesterThreshold1.run( - 'Regular expressions should not be too complicated with threshold 1', - rule, - { - valid: [ - { - code: ` + const ruleTesterThreshold1 = new RuleTester(); + ruleTesterThreshold1.run( + 'Regular expressions should not be too complicated with threshold 1', + rule, + { + valid: [ + { + code: ` const part1 = 'x*'; const part2 = 'y*'; RegExp(part1 + part2); `, - options: createOptions(1), - }, - ], - invalid: [ - { - code: `RegExp('x*' + 'y*')`, - errors: 1, - options: createOptions(1), - }, - { - code: `RegExp('x*' + 'y*' + 'z*')`, - errors: 1, - options: createOptions(1), - }, - { - code: ` + options: createOptions(1), + }, + ], + invalid: [ + { + code: `RegExp('x*' + 'y*')`, + errors: 1, + options: createOptions(1), + }, + { + code: `RegExp('x*' + 'y*' + 'z*')`, + errors: 1, + options: createOptions(1), + }, + { + code: ` const part1 = 'x*' + 'y*'; const part2 = 'a*' + 'b*'; RegExp(part1 + part2); `, - errors: [ - { - message: JSON.stringify({ - message: `Simplify this regular expression to reduce its complexity from 2 to the 1 allowed.`, - secondaryLocations: [ - { message: `+1`, column: 24, line: 2, endColumn: 25, endLine: 2 }, - { message: `+1`, column: 31, line: 2, endColumn: 32, endLine: 2 }, - ], - cost: 1, - }), - line: 2, - endLine: 2, - column: 23, - endColumn: 27, - }, - { - message: JSON.stringify({ - message: `Simplify this regular expression to reduce its complexity from 2 to the 1 allowed.`, - secondaryLocations: [ - { message: `+1`, column: 24, line: 3, endColumn: 25, endLine: 3 }, - { message: `+1`, column: 31, line: 3, endColumn: 32, endLine: 3 }, - ], - cost: 1, - }), - line: 3, - endLine: 3, - column: 23, - endColumn: 27, - }, - ], - options: createOptions(1), - }, - ], - }, - ); + errors: [ + { + message: JSON.stringify({ + message: `Simplify this regular expression to reduce its complexity from 2 to the 1 allowed.`, + secondaryLocations: [ + { message: `+1`, column: 24, line: 2, endColumn: 25, endLine: 2 }, + { message: `+1`, column: 31, line: 2, endColumn: 32, endLine: 2 }, + ], + cost: 1, + }), + line: 2, + endLine: 2, + column: 23, + endColumn: 27, + }, + { + message: JSON.stringify({ + message: `Simplify this regular expression to reduce its complexity from 2 to the 1 allowed.`, + secondaryLocations: [ + { message: `+1`, column: 24, line: 3, endColumn: 25, endLine: 3 }, + { message: `+1`, column: 31, line: 3, endColumn: 32, endLine: 3 }, + ], + cost: 1, + }), + line: 3, + endLine: 3, + column: 23, + endColumn: 27, + }, + ], + options: createOptions(1), + }, + ], + }, + ); - const typeAwareRuleTester = new RuleTester(); - typeAwareRuleTester.run( - 'Regular expressions should not be too complicated with type information', - rule, - { - valid: [ - { - code: `'str'.search('abc')`, - options: createOptions(0), - }, - ], - invalid: [ - { - code: `'str'.search('x*')`, - errors: [ - { - message: JSON.stringify({ - message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, - secondaryLocations: [ - { message: `+1`, column: 15, line: 1, endColumn: 16, endLine: 1 }, - ], - cost: 1, - }), - line: 1, - endLine: 1, - column: 14, - endColumn: 18, - }, - ], - options: createOptions(0), - }, - ], - }, - ); + const typeAwareRuleTester = new RuleTester(); + typeAwareRuleTester.run( + 'Regular expressions should not be too complicated with type information', + rule, + { + valid: [ + { + code: `'str'.search('abc')`, + options: createOptions(0), + }, + ], + invalid: [ + { + code: `'str'.search('x*')`, + errors: [ + { + message: JSON.stringify({ + message: `Simplify this regular expression to reduce its complexity from 1 to the 0 allowed.`, + secondaryLocations: [ + { message: `+1`, column: 15, line: 1, endColumn: 16, endLine: 1 }, + ], + cost: 1, + }), + line: 1, + endLine: 1, + column: 14, + endColumn: 18, + }, + ], + options: createOptions(0), + }, + ], + }, + ); - const ruleTesterDefaultThreshold = new RuleTester(); - ruleTesterDefaultThreshold.run( - 'Regular expressions should not be too complicated with default threshold', - rule, - { - valid: [ - { - code: `/ /`, - }, - ], - invalid: [ - { - code: `/^(?:(?:31(\\/|-|\\.)(?:0?[13578]|1[02]))\\1|(?:(?:29|30)(\\/|-|\\.)(?:0?[13-9]|1[0-2])\\2))(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$|^(?:29(\\/|-|\.)0?2\\3(?:(?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\\d|2[0-8])(\\/|-|\\.)(?:(?:0?[1-9])|(?:1[0-2]))\\4(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$/`, - errors: 1, - }, - ], - }, - ); + const ruleTesterDefaultThreshold = new RuleTester(); + ruleTesterDefaultThreshold.run( + 'Regular expressions should not be too complicated with default threshold', + rule, + { + valid: [ + { + code: `/ /`, + }, + ], + invalid: [ + { + code: `/^(?:(?:31(\\/|-|\\.)(?:0?[13578]|1[02]))\\1|(?:(?:29|30)(\\/|-|\\.)(?:0?[13-9]|1[0-2])\\2))(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$|^(?:29(\\/|-|\.)0?2\\3(?:(?:(?:1[6-9]|[2-9]\\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\\d|2[0-8])(\\/|-|\\.)(?:(?:0?[1-9])|(?:1[0-2]))\\4(?:(?:1[6-9]|[2-9]\\d)?\\d{2})$/`, + errors: 1, + }, + ], + }, + ); + }); }); diff --git a/packages/jsts/src/rules/S5850/unit.test.ts b/packages/jsts/src/rules/S5850/unit.test.ts index 5284cfb1c3..686db2e430 100644 --- a/packages/jsts/src/rules/S5850/unit.test.ts +++ b/packages/jsts/src/rules/S5850/unit.test.ts @@ -16,88 +16,90 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5850', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Anchor precedence', rule, { - valid: [ - { - code: `/^(?:a|b|c)$/`, - }, - { - code: `/(?:^a)|b|(?:c$)/`, - }, - { - code: `/^abc$/`, - }, - { - code: `/a|b|c/`, - }, - { - code: `/^a$|^b$|^c$/`, - }, - { - code: `/^a$|b|c/`, - }, - { - code: `/a|b|^c$/`, - }, - { - code: `/^a|^b$|c$/`, - }, - { - code: `/^a|^b|c$/`, - }, - { - code: `/^a|b$|c$/`, - }, - { - code: `/^a|^b|c/`, // More likely intential as there are multiple anchored alternatives - }, - { - code: `/aa|bb|cc/`, - }, - { - code: `/^/`, - }, - { - code: `/^[abc]$/`, - }, - { - code: `/|/`, - }, - ], - invalid: [ - { - code: `/^a|b|c$/`, - errors: [ - { - message: - 'Group parts of the regex together to make the intended operator precedence explicit.', - line: 1, - endLine: 1, - column: 2, - endColumn: 9, - }, - ], - }, - { - code: `/^a|b|cd/`, - errors: 1, - }, - { - code: `/a|b|c$/`, - errors: 1, - }, - { - code: `/^a|(b|c)/`, - errors: 1, - }, - { - code: `/(a|b)|c$/`, - errors: 1, - }, - ], + it('S5850', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Anchor precedence', rule, { + valid: [ + { + code: `/^(?:a|b|c)$/`, + }, + { + code: `/(?:^a)|b|(?:c$)/`, + }, + { + code: `/^abc$/`, + }, + { + code: `/a|b|c/`, + }, + { + code: `/^a$|^b$|^c$/`, + }, + { + code: `/^a$|b|c/`, + }, + { + code: `/a|b|^c$/`, + }, + { + code: `/^a|^b$|c$/`, + }, + { + code: `/^a|^b|c$/`, + }, + { + code: `/^a|b$|c$/`, + }, + { + code: `/^a|^b|c/`, // More likely intential as there are multiple anchored alternatives + }, + { + code: `/aa|bb|cc/`, + }, + { + code: `/^/`, + }, + { + code: `/^[abc]$/`, + }, + { + code: `/|/`, + }, + ], + invalid: [ + { + code: `/^a|b|c$/`, + errors: [ + { + message: + 'Group parts of the regex together to make the intended operator precedence explicit.', + line: 1, + endLine: 1, + column: 2, + endColumn: 9, + }, + ], + }, + { + code: `/^a|b|cd/`, + errors: 1, + }, + { + code: `/a|b|c$/`, + errors: 1, + }, + { + code: `/^a|(b|c)/`, + errors: 1, + }, + { + code: `/(a|b)|c$/`, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S5852/unit.test.ts b/packages/jsts/src/rules/S5852/unit.test.ts index e890a59a86..9219ebdca5 100644 --- a/packages/jsts/src/rules/S5852/unit.test.ts +++ b/packages/jsts/src/rules/S5852/unit.test.ts @@ -16,52 +16,53 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5852', () => { - const ruleTesterTs = new RuleTester(); - ruleTesterTs.run('redos', rule, { - valid: [ - { - code: ` + it('S5852', () => { + const ruleTesterTs = new RuleTester(); + ruleTesterTs.run('redos', rule, { + valid: [ + { + code: ` /a|b|c/; /x*x*/; /a*(ab)*/; /x*|x*/; /a*b*/; `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` /(a+)+$/ `, - errors: [ - { - message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, - line: 2, - endLine: 2, - column: 9, - endColumn: 17, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, + line: 2, + endLine: 2, + column: 9, + endColumn: 17, + }, + ], + }, + { + code: ` /([^,]*,)*/; // FP? compliant in SonarJava tests `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` new RegExp('x*$'); `, - errors: 1, - }, - { - // Real vulnerabilities - code: ` + errors: 1, + }, + { + // Real vulnerabilities + code: ` protocol.trim().split(/ *, */); var matcher = /.+\\@.+\\..+/; enclosure = /[{[].*\\/.*[}\\]]$/; @@ -76,58 +77,59 @@ describe('S5852', () => { const match = /^data:(?.*?),(?.*?)(?:#(?.*))?$/.exec(urlString); const match = /^data:(?[^,]*?),(?[^#]*?)(?:#(?.*))?$/.exec(urlString); // OK, fix for previous one `, - errors: [ - { - message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, - line: 2, - }, - { - message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, - line: 3, - }, - { - message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, - line: 4, - }, - { - message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, - line: 5, - }, - { - message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, - line: 6, - }, - { - message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, - line: 7, - }, - { - message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, - line: 8, - }, - { - message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, - line: 9, - }, - { - message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, - line: 10, - }, - { - message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, - line: 11, - }, - { - message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, - line: 13, - }, - ], - }, - { - // fails on Node 10 - code: `new RegExp('[\\x09\\x0A]*$');`, - errors: 1, - }, - ], + errors: [ + { + message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, + line: 2, + }, + { + message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, + line: 3, + }, + { + message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, + line: 4, + }, + { + message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, + line: 5, + }, + { + message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, + line: 6, + }, + { + message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, + line: 7, + }, + { + message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, + line: 8, + }, + { + message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, + line: 9, + }, + { + message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, + line: 10, + }, + { + message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, + line: 11, + }, + { + message: `Make sure the regex used here, which is vulnerable to super-linear runtime due to backtracking, cannot lead to denial of service.`, + line: 13, + }, + ], + }, + { + // fails on Node 10 + code: `new RegExp('[\\x09\\x0A]*$');`, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S5856/unit.test.ts b/packages/jsts/src/rules/S5856/unit.test.ts index 420988c511..2829533218 100644 --- a/packages/jsts/src/rules/S5856/unit.test.ts +++ b/packages/jsts/src/rules/S5856/unit.test.ts @@ -16,74 +16,76 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5856', () => { - const ruleTesterTs = new RuleTester(); - ruleTesterTs.run('Malformed regular expressions', rule, { - valid: [ - { - code: `new RegExp("\\\\(\\\\[");`, - }, - { - code: `new RegExp("\\\\(\\\\[", "g");`, - }, - { - code: `str.match("\\\\(\\\\[");`, - }, - { - code: `str.replace("([", "{");`, - }, - { - code: `'xxx'.match();`, - }, - { - code: `foo.match('[');`, - }, - { - code: ` + it('S5856', () => { + const ruleTesterTs = new RuleTester(); + ruleTesterTs.run('Malformed regular expressions', rule, { + valid: [ + { + code: `new RegExp("\\\\(\\\\[");`, + }, + { + code: `new RegExp("\\\\(\\\\[", "g");`, + }, + { + code: `str.match("\\\\(\\\\[");`, + }, + { + code: `str.replace("([", "{");`, + }, + { + code: `'xxx'.match();`, + }, + { + code: `foo.match('[');`, + }, + { + code: ` new RegExp(); new RegExp('foo', 4); `, - }, - ], - invalid: [ - { - code: `new RegExp("([");`, - errors: [ - { - message: 'Invalid regular expression: /([/: Unterminated character class', - line: 1, - column: 1, - endLine: 1, - endColumn: 17, - }, - ], - }, - { - code: `'xxx'.match("([");`, - errors: [ - { - message: 'Invalid regular expression: /([/: Unterminated character class', - line: 1, - column: 1, - endLine: 1, - endColumn: 18, - }, - ], - }, - { - code: `new RegExp("\\\\(\\\\[", "a");`, - errors: [ - { - message: "Invalid flags supplied to RegExp constructor 'a'", - line: 1, - column: 1, - endLine: 1, - endColumn: 26, - }, - ], - }, - ], + }, + ], + invalid: [ + { + code: `new RegExp("([");`, + errors: [ + { + message: 'Invalid regular expression: /([/: Unterminated character class', + line: 1, + column: 1, + endLine: 1, + endColumn: 17, + }, + ], + }, + { + code: `'xxx'.match("([");`, + errors: [ + { + message: 'Invalid regular expression: /([/: Unterminated character class', + line: 1, + column: 1, + endLine: 1, + endColumn: 18, + }, + ], + }, + { + code: `new RegExp("\\\\(\\\\[", "a");`, + errors: [ + { + message: "Invalid flags supplied to RegExp constructor 'a'", + line: 1, + column: 1, + endLine: 1, + endColumn: 26, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S5860/unit.test.ts b/packages/jsts/src/rules/S5860/unit.test.ts index f0af6b9420..d6447cca75 100644 --- a/packages/jsts/src/rules/S5860/unit.test.ts +++ b/packages/jsts/src/rules/S5860/unit.test.ts @@ -16,32 +16,33 @@ */ import { rule } from './index.js'; import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5860', () => { - const typeAwareRuleTester = new RuleTester(); - typeAwareRuleTester.run('Regular expressions named groups should be used', rule, { - valid: [ - { - code: ` + it('S5860', () => { + const typeAwareRuleTester = new RuleTester(); + typeAwareRuleTester.run('Regular expressions named groups should be used', rule, { + valid: [ + { + code: ` const pattern = /(?\\w)/; const matched = 'str'.matchAll(pattern); if (matched) { matched.groups.foo; } `, - }, - { - code: ` + }, + { + code: ` const pattern = /(?\\w)/; const matched = 'str'.match(pattern); if (matched) { matched.groups.foo; } `, - }, - { - code: ` + }, + { + code: ` const pattern = /(?\\w)(?\\w)(?\\w)/; const matched = 'str'.match(pattern); if (matched) { @@ -50,43 +51,43 @@ describe('S5860', () => { matched.groups.baz; } `, - }, - { - code: ` + }, + { + code: ` const pattern = /(?\\w)/; const matched = pattern.exec('str'); if (matched) { matched.indices.groups.foo; } `, - }, - { - code: ` + }, + { + code: ` const pattern = 12345; const matched = 'str'.matchAll(pattern); if (matched) { matched.groups.foo; } `, - }, - { - code: ` + }, + { + code: ` const matched = 'str'.matchAll(unknownPattern); if (matched) { matched.groups.foo; } `, - }, - { - code: ` + }, + { + code: ` const matched = 'str'.matchAll(/(?\\w)/); if (matched) { matched.groups!.foo; } `, - }, - { - code: ` + }, + { + code: ` function foo(unknownPattern) { const matched = 'str'.matchAll(unknownPattern); if (matched) { @@ -94,62 +95,62 @@ describe('S5860', () => { } } `, - }, - { - code: ` + }, + { + code: ` const pattern = /(?\\w)/; const result = 'str'.replace(pattern, '$'); `, - }, - { - code: ` + }, + { + code: ` const result = 'str'.replace(unknownPattern, '$'); `, - }, - { - code: `/(?\\w)/ // unused 'foo': ignored because pattern never matched`, - }, - { - code: `RegExp('(?\\w)') // unused 'foo': ignored because pattern never matched`, - }, - { - code: `new RegExp('(?\\w)') // unused 'foo': ignored because pattern never matched`, - }, - { - code: ` + }, + { + code: `/(?\\w)/ // unused 'foo': ignored because pattern never matched`, + }, + { + code: `RegExp('(?\\w)') // unused 'foo': ignored because pattern never matched`, + }, + { + code: `new RegExp('(?\\w)') // unused 'foo': ignored because pattern never matched`, + }, + { + code: ` const pattern = /(?\\w)/; // unused 'foo': ignored because pattern never matched const matched = 'str'.matchAll(/* missing pattern */); if (matched) { matched.groups.foo; } `, - }, - { - code: ` + }, + { + code: ` const pattern = /(?\\w)/; // unused 'foo': ignored because pattern never const matched = match(pattern); // not 'String.prototype.match' method call if (matched) { matched.groups.foo; } `, - }, - { - code: ` + }, + { + code: ` const pattern = /(?\\w)/; // unused 'foo': ignored because pattern never matched const found = pattern.test('str'); // using 'RegExp.prototype.test' if (found) { /* ... */ } `, - }, - { - code: ` + }, + { + code: ` const pattern = /(?\\w)(?\\w)/; // unused 'foo': ignored because pattern never matched const result = 'str'.replace(pattern, '$ $'); `, - }, - { - code: ` + }, + { + code: ` const pattern = /(?\\w)/; // unused 'foo': ignored because undeclared pattern undeclaredMatch = 'str'.match(pattern); if (matched) { @@ -157,63 +158,63 @@ describe('S5860', () => { undeclaredMatch.groups.foo; } `, - }, - { - code: ` + }, + { + code: ` let pattern; pattern = pattern; const matched = 'str'.matchAll(pattern); `, - }, - { - code: ` + }, + { + code: ` let pattern1, pattern2, pattern3; pattern1 = pattern3; pattern2 = pattern1; pattern3 = pattern2; const matched = 'str'.matchAll(pattern3); `, - }, - { - code: ` + }, + { + code: ` const pattern = /(?\\w)(?\\w)/; const matched = 'str'.match(pattern); if (matched) { const { foo, bar: b } = matched.groups; } `, - }, - { - code: ` + }, + { + code: ` const pattern = /(?\\w)(?\\w)/; const matched = 'str'.match(pattern); if (matched) { ({ foo, bar } = matched.groups); } `, - }, - { - code: ` + }, + { + code: ` const pattern = /(?\\w)/; const matched = 'str'.matchAll(pattern); if (matched) { matched.groups['foo']; } `, - }, - { - code: ` + }, + { + code: ` const pattern = /(?\\w)/; const matched = pattern.exec('str'); if (matched) { matched.indices.groups['foo']; } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const pattern = /(?\\w)/; const matched = 'str'.matchAll(pattern); if (matched) { @@ -221,10 +222,10 @@ describe('S5860', () => { matched[2]; // ignored as it doesn't exist } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const pattern = /(?\\w)/; // ^^^^^^^^^^^ const matched = 'str'.match(pattern); @@ -233,24 +234,24 @@ describe('S5860', () => { // ^ } `, - errors: [ - { - message: JSON.stringify({ - message: `Directly use 'foo' instead of its group number.`, - secondaryLocations: [ - { message: `Group 'foo'`, column: 25, line: 2, endColumn: 35, endLine: 2 }, - ], - }), - line: 6, - endLine: 6, - column: 19, - endColumn: 20, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `Directly use 'foo' instead of its group number.`, + secondaryLocations: [ + { message: `Group 'foo'`, column: 25, line: 2, endColumn: 35, endLine: 2 }, + ], + }), + line: 6, + endLine: 6, + column: 19, + endColumn: 20, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const FOO_IDX = 1; const pattern = /(?\\w)/; const matched = 'str'.match(pattern); @@ -258,10 +259,10 @@ describe('S5860', () => { matched[FOO_IDX]; // Noncompliant: 'foo' referenced by index } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const pattern = /(abc)(?\\w)/; const matched = 'str'.match(pattern); if (matched) { @@ -269,10 +270,10 @@ describe('S5860', () => { matched[2]; // Noncompliant: 'foo' referenced by index } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const pattern = /(?\\w)(?\\w)/; // Noncompliant: unused 'foo' // ^^^^^^^^^^^ // ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -281,44 +282,44 @@ describe('S5860', () => { matched.groups.bar; } `, - errors: [ - { - message: JSON.stringify({ - message: 'Use the named groups of this regex or remove the names.', - secondaryLocations: [ - { message: `Named group 'foo'`, column: 25, line: 2, endColumn: 35, endLine: 2 }, - ], - }), - line: 2, - endLine: 2, - column: 25, - endColumn: 47, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: 'Use the named groups of this regex or remove the names.', + secondaryLocations: [ + { message: `Named group 'foo'`, column: 25, line: 2, endColumn: 35, endLine: 2 }, + ], + }), + line: 2, + endLine: 2, + column: 25, + endColumn: 47, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const pattern = /(?\\w)/; // Noncompliant: unused 'foo' const matched = 'str'.match(pattern); if (matched) { matched[UNKNOWN_IDX]; } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const pattern = /(?\\w)/; // Noncompliant: unused 'foo' const matched = 'str'.match(pattern); if (matched) { matched['non-number index']; } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const pattern = /(?\\w)/; // ^^^^^^^^^^^ const matched = 'str'.match(pattern); @@ -328,34 +329,34 @@ describe('S5860', () => { // ^^^ } `, - errors: [ - { - message: JSON.stringify({ - message: `There is no group named 'bar' in the regular expression.`, - secondaryLocations: [ - { message: `Named group 'foo'`, column: 25, line: 2, endColumn: 35, endLine: 2 }, - ], - }), - line: 7, - endLine: 7, - column: 26, - endColumn: 29, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `There is no group named 'bar' in the regular expression.`, + secondaryLocations: [ + { message: `Named group 'foo'`, column: 25, line: 2, endColumn: 35, endLine: 2 }, + ], + }), + line: 7, + endLine: 7, + column: 26, + endColumn: 29, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const pattern = /(?\\w)(?\\w)(?\\w)/; // Noncompliant: unused 'foo', 'baz' const matched = 'str'.match(pattern); if (matched) { matched.groups.bar; } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const pattern = /(?\\w)/; // Noncompliant: unused 'foo' const matched = pattern.exec('str'); if (matched) { @@ -363,30 +364,30 @@ describe('S5860', () => { matched.groups[foo]; } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const pattern = /(?\\w)/; // Noncompliant: unused 'foo' const matched = 'str'.match(pattern); if (matched) { matched.groupz.foo; // Intentional typo 'groupz' } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const pattern = /(?\\w)/; // Noncompliant: unused 'foo' const matched = pattern.exec('str'); if (matched) { matched.indices.groupz.foo; // Intentional typo 'groupz' } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const pattern = /(?\\w)/; const matched = pattern.exec('str'); if (matched) { @@ -394,10 +395,10 @@ describe('S5860', () => { matched[2]; } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const pattern = /(?\\w)/; // ^^^^^^^^^^^ const matched = pattern.exec('str'); @@ -407,24 +408,24 @@ describe('S5860', () => { // ^^^ } `, - errors: [ - { - message: JSON.stringify({ - message: `There is no group named 'bar' in the regular expression.`, - secondaryLocations: [ - { message: `Named group 'foo'`, column: 25, line: 2, endColumn: 35, endLine: 2 }, - ], - }), - line: 7, - endLine: 7, - column: 34, - endColumn: 37, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `There is no group named 'bar' in the regular expression.`, + secondaryLocations: [ + { message: `Named group 'foo'`, column: 25, line: 2, endColumn: 35, endLine: 2 }, + ], + }), + line: 7, + endLine: 7, + column: 34, + endColumn: 37, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const pattern = /(?\\w)/; // Noncompliant: unused 'foo' const matched = pattern.exec('str'); if (matched) { @@ -433,40 +434,40 @@ describe('S5860', () => { matched.indices.groups[foo]; } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const pattern = /(?\\w)(?\\w)/; const result = 'str'.replace(pattern, '$2 $3'); // Noncompliant: 'foo' referenced by index `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const pattern = /(?\\w)/; // ^^^^^^^^^^ const result = 'str'.replace(pattern, '$1'); // Noncompliant: 'foo' referenced by index // ^^^^ `, - errors: [ - { - message: JSON.stringify({ - message: 'Directly use the group names instead of their numbers.', - secondaryLocations: [ - { message: `Group 'foo'`, column: 25, line: 2, endColumn: 35, endLine: 2 }, - ], - }), - line: 4, - endLine: 4, - column: 47, - endColumn: 51, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: 'Directly use the group names instead of their numbers.', + secondaryLocations: [ + { message: `Group 'foo'`, column: 25, line: 2, endColumn: 35, endLine: 2 }, + ], + }), + line: 4, + endLine: 4, + column: 47, + endColumn: 51, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const pattern = /(?\\w)/; let declaredMatch; declaredMatch = 'str'.match(pattern); @@ -474,10 +475,10 @@ describe('S5860', () => { declaredMatch[1]; // Noncompliant: 'foo' referenced by index } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const pattern = '(?\\w)(?\\w)(?\\w)'; // Noncompliant: unused 'baz' const matched = 'str'.match(pattern); if (matched) { @@ -486,36 +487,36 @@ describe('S5860', () => { matched.indices.groups.qux; // Noncompliant: 'qux' doesn't exist } `, - errors: 3, - }, - { - code: ` + errors: 3, + }, + { + code: ` /(?\\w)\\1(?\\w)\\k(?\\w)/; // Noncompliant: 'foo' referenced by index // ^^^ // ^^^^^^^^^^^ `, - errors: [ - { - message: JSON.stringify({ - message: `Directly use 'foo' instead of its group number.`, - secondaryLocations: [ - { message: `Group 'foo'`, column: 9, line: 2, endColumn: 19, endLine: 2 }, - ], - }), - line: 2, - endLine: 2, - column: 20, - endColumn: 22, - }, - ], - options: ['sonar-runtime'], - }, - { - code: `'str'.search('(?\\w)\\\\1(?\\w)\\\\k(?\\w)'); // Noncompliant: 'foo' referenced by index`, - errors: 1, - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `Directly use 'foo' instead of its group number.`, + secondaryLocations: [ + { message: `Group 'foo'`, column: 9, line: 2, endColumn: 19, endLine: 2 }, + ], + }), + line: 2, + endLine: 2, + column: 20, + endColumn: 22, + }, + ], + options: ['sonar-runtime'], + }, + { + code: `'str'.search('(?\\w)\\\\1(?\\w)\\\\k(?\\w)'); // Noncompliant: 'foo' referenced by index`, + errors: 1, + }, + { + code: ` const pattern = /(?\\w)(?\\w)/; // Noncompliant: unused 'foo' // ^^^^^^^^^^^ // ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -524,24 +525,24 @@ describe('S5860', () => { const { bar } = matched.groups; } `, - errors: [ - { - message: JSON.stringify({ - message: 'Use the named groups of this regex or remove the names.', - secondaryLocations: [ - { message: `Named group 'foo'`, column: 25, line: 2, endColumn: 35, endLine: 2 }, - ], - }), - line: 2, - endLine: 2, - column: 25, - endColumn: 47, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: 'Use the named groups of this regex or remove the names.', + secondaryLocations: [ + { message: `Named group 'foo'`, column: 25, line: 2, endColumn: 35, endLine: 2 }, + ], + }), + line: 2, + endLine: 2, + column: 25, + endColumn: 47, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const pattern = /(?\\w)(?\\w)/; // Noncompliant: unused 'foo' // ^^^^^^^^^^^ // ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -550,60 +551,60 @@ describe('S5860', () => { ({ bar } = matched.groups); } `, - errors: [ - { - message: JSON.stringify({ - message: 'Use the named groups of this regex or remove the names.', - secondaryLocations: [ - { message: `Named group 'foo'`, column: 25, line: 2, endColumn: 35, endLine: 2 }, - ], - }), - line: 2, - endLine: 2, - column: 25, - endColumn: 47, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: 'Use the named groups of this regex or remove the names.', + secondaryLocations: [ + { message: `Named group 'foo'`, column: 25, line: 2, endColumn: 35, endLine: 2 }, + ], + }), + line: 2, + endLine: 2, + column: 25, + endColumn: 47, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const pattern = /(?\\w)(?\\w)/; // Noncompliant: unused 'foo', 'bar' const matched = 'str'.match(pattern); if (matched) { ({ [abc]: def, ...hij} = matched.groups); } `, - errors: 2, - }, - { - code: ` + errors: 2, + }, + { + code: ` const pattern = /(?\\w)(?\\w)/; // Noncompliant: unused 'foo' const matched = 'str'.match(pattern); if (matched) { matched.groups['bar']; } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const pattern = /(?\\w)(?\\w)/; // Noncompliant: unused 'foo' const matched = pattern.exec('str'); if (matched) { matched.indices.groups['bar']; } `, - errors: 1, - }, - ], - }); + errors: 1, + }, + ], + }); - const ruleTester = new DefaultParserRuleTester(); - ruleTester.run('"unused-named-groups" reports nothing without types', rule, { - valid: [ - { - code: ` + const ruleTester = new DefaultParserRuleTester(); + ruleTester.run('"unused-named-groups" reports nothing without types', rule, { + valid: [ + { + code: ` const pattern = /(?\\w)/ const matched = 'str'.matchAll(pattern); if (matched) { @@ -612,9 +613,9 @@ describe('S5860', () => { matched.groups.bar; } `, - }, - { - code: ` + }, + { + code: ` const pattern = /(?\\w)/ const matched = pattern.exec('str'); if (matched) { @@ -623,8 +624,9 @@ describe('S5860', () => { matched.indices.groups.bar; } `, - }, - ], - invalid: [], + }, + ], + invalid: [], + }); }); }); diff --git a/packages/jsts/src/rules/S5863/unit.test.ts b/packages/jsts/src/rules/S5863/unit.test.ts index 6aeebe5d6f..ff4c226d18 100644 --- a/packages/jsts/src/rules/S5863/unit.test.ts +++ b/packages/jsts/src/rules/S5863/unit.test.ts @@ -16,27 +16,29 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5863', () => { - const ruleTester = new RuleTester(); + it('S5863', () => { + const ruleTester = new RuleTester(); - // Main test cases are in the file comment-based fixture file. - // Here we are testing that no issues are reported when no 'chai' import. + // Main test cases are in the file comment-based fixture file. + // Here we are testing that no issues are reported when no 'chai' import. - ruleTester.run('Assertions should not be given twice the same argument', rule, { - valid: [ - { - code: `assert.equal(obj, obj);`, - }, - ], - invalid: [ - { - code: ` + ruleTester.run('Assertions should not be given twice the same argument', rule, { + valid: [ + { + code: `assert.equal(obj, obj);`, + }, + ], + invalid: [ + { + code: ` const chai = require('chai'); assert.equal(obj, obj);`, - errors: [{ message: 'Replace this argument or its duplicate.', line: 3 }], - }, - ], + errors: [{ message: 'Replace this argument or its duplicate.', line: 3 }], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S5867/unit.test.ts b/packages/jsts/src/rules/S5867/unit.test.ts index 0688a603b4..49cbfc53f2 100644 --- a/packages/jsts/src/rules/S5867/unit.test.ts +++ b/packages/jsts/src/rules/S5867/unit.test.ts @@ -16,108 +16,110 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5867', () => { - const ruleTester = new RuleTester(); - ruleTester.run(`Regular expressions using Unicode constructs with the 'u' flag`, rule, { - valid: [ - { - code: `/\\u{1234}/u`, - }, - { - code: `/\\u{12346}/u`, - }, - { - code: `/\\p{Alpha}/u`, - }, - { - code: `/\\p{Script=Latin}/u`, - }, - { - code: `/\\P{Alpha}/u`, - }, - { - code: `/[\\p{Alpha}]/u`, - }, - { - code: `/\\p/`, - }, - { - code: `/\\p{/`, - }, - { - code: `/\\p{a/`, - }, - { - code: `/\\p{a=/`, - }, - { - code: `/\\p{a=b/`, - }, - { - code: `/a+/u`, - }, - { - code: `/\\u{12}/`, - }, - { - code: `/\\u{12,34}/`, - }, - ], - invalid: [ - { - code: `/\\u{1234}/`, - errors: [ - { - message: JSON.stringify({ - message: `Enable the 'u' flag for this regex using Unicode constructs.`, - secondaryLocations: [ - { message: `Unicode character`, column: 1, line: 1, endColumn: 9, endLine: 1 }, - ], - }), - line: 1, - endLine: 1, - column: 1, - endColumn: 11, - }, - ], - options: ['sonar-runtime'], - }, - { - code: `/\\u{12346}/`, - errors: 1, - }, - { - code: `/\\p{Alpha}/`, - errors: [ - { - message: JSON.stringify({ - message: `Enable the 'u' flag for this regex using Unicode constructs.`, - secondaryLocations: [ - { message: `Unicode property`, column: 1, line: 1, endColumn: 11, endLine: 1 }, - ], - }), - line: 1, - endLine: 1, - column: 1, - endColumn: 12, - }, - ], - options: ['sonar-runtime'], - }, - { - code: `/\\P{Alpha}/`, - errors: 1, - }, - { - code: `/\\P{Script=Latin}/`, - errors: 1, - }, - { - code: `/[\\p{Alpha}]/`, - errors: 1, - }, - ], + it('S5867', () => { + const ruleTester = new RuleTester(); + ruleTester.run(`Regular expressions using Unicode constructs with the 'u' flag`, rule, { + valid: [ + { + code: `/\\u{1234}/u`, + }, + { + code: `/\\u{12346}/u`, + }, + { + code: `/\\p{Alpha}/u`, + }, + { + code: `/\\p{Script=Latin}/u`, + }, + { + code: `/\\P{Alpha}/u`, + }, + { + code: `/[\\p{Alpha}]/u`, + }, + { + code: `/\\p/`, + }, + { + code: `/\\p{/`, + }, + { + code: `/\\p{a/`, + }, + { + code: `/\\p{a=/`, + }, + { + code: `/\\p{a=b/`, + }, + { + code: `/a+/u`, + }, + { + code: `/\\u{12}/`, + }, + { + code: `/\\u{12,34}/`, + }, + ], + invalid: [ + { + code: `/\\u{1234}/`, + errors: [ + { + message: JSON.stringify({ + message: `Enable the 'u' flag for this regex using Unicode constructs.`, + secondaryLocations: [ + { message: `Unicode character`, column: 1, line: 1, endColumn: 9, endLine: 1 }, + ], + }), + line: 1, + endLine: 1, + column: 1, + endColumn: 11, + }, + ], + options: ['sonar-runtime'], + }, + { + code: `/\\u{12346}/`, + errors: 1, + }, + { + code: `/\\p{Alpha}/`, + errors: [ + { + message: JSON.stringify({ + message: `Enable the 'u' flag for this regex using Unicode constructs.`, + secondaryLocations: [ + { message: `Unicode property`, column: 1, line: 1, endColumn: 11, endLine: 1 }, + ], + }), + line: 1, + endLine: 1, + column: 1, + endColumn: 12, + }, + ], + options: ['sonar-runtime'], + }, + { + code: `/\\P{Alpha}/`, + errors: 1, + }, + { + code: `/\\P{Script=Latin}/`, + errors: 1, + }, + { + code: `/[\\p{Alpha}]/`, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S5868/unit.test.ts b/packages/jsts/src/rules/S5868/unit.test.ts index 2926ec0bbf..5fb48a0cd4 100644 --- a/packages/jsts/src/rules/S5868/unit.test.ts +++ b/packages/jsts/src/rules/S5868/unit.test.ts @@ -16,392 +16,394 @@ */ import { DefaultParserRuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5868', () => { - const ruleTester = new DefaultParserRuleTester(); + it('S5868', () => { + const ruleTester = new DefaultParserRuleTester(); - const combiningClass = c => - `Move this Unicode combined character '${c}' outside of the character class`; + const combiningClass = c => + `Move this Unicode combined character '${c}' outside of the character class`; - function surrogatePair(c, output?, start?: number, end?: number) { - const error = { - message: `Move this Unicode surrogate pair '${c}' outside of the character class or use 'u' flag`, - }; - if (output) { - error['suggestions'] = [{ desc: "Add unicode 'u' flag to regex", output }]; + function surrogatePair(c, output?, start?: number, end?: number) { + const error = { + message: `Move this Unicode surrogate pair '${c}' outside of the character class or use 'u' flag`, + }; + if (output) { + error['suggestions'] = [{ desc: "Add unicode 'u' flag to regex", output }]; + } + if (start != null) { + error['column'] = start; + } + if (end != null) { + error['endColumn'] = end; + } + return [error]; } - if (start != null) { - error['column'] = start; - } - if (end != null) { - error['endColumn'] = end; - } - return [error]; - } - const modifiedEmoji = c => - `Move this Unicode modified Emoji '${c}' outside of the character class`; - const regionalIndicator = c => - `Move this Unicode regional indicator '${c}' outside of the character class`; - const zwj = 'Move this Unicode joined character sequence outside of the character class'; + const modifiedEmoji = c => + `Move this Unicode modified Emoji '${c}' outside of the character class`; + const regionalIndicator = c => + `Move this Unicode regional indicator '${c}' outside of the character class`; + const zwj = 'Move this Unicode joined character sequence outside of the character class'; - ruleTester.run('', rule, { - valid: [ - { code: 'var r = /[\\uD83D\\d\\uDC4D]/' }, - { code: 'var r = /[\\uD83D-\\uDC4D]/' }, - { code: 'var r = /[👍]/u' }, - { code: 'var r = /[\\uD83D\\uDC4D]/u' }, - { code: 'var r = /[\\u{1F44D}]/u' }, - { code: 'var r = /❇️/' }, - { code: 'var r = /Á/' }, - { code: 'var r = /[❇]/' }, - { code: 'var r = /👶🏻/' }, - { code: 'var r = /[👶]/u' }, - { code: 'var r = /🇯🇵/' }, - { code: 'var r = /[JP]/' }, - { code: 'var r = /👨‍👩‍👦/' }, + ruleTester.run('', rule, { + valid: [ + { code: 'var r = /[\\uD83D\\d\\uDC4D]/' }, + { code: 'var r = /[\\uD83D-\\uDC4D]/' }, + { code: 'var r = /[👍]/u' }, + { code: 'var r = /[\\uD83D\\uDC4D]/u' }, + { code: 'var r = /[\\u{1F44D}]/u' }, + { code: 'var r = /❇️/' }, + { code: 'var r = /Á/' }, + { code: 'var r = /[❇]/' }, + { code: 'var r = /👶🏻/' }, + { code: 'var r = /[👶]/u' }, + { code: 'var r = /🇯🇵/' }, + { code: 'var r = /[JP]/' }, + { code: 'var r = /👨‍👩‍👦/' }, - { code: 'var r = /[\\uD83D]/' }, - { code: 'var r = /[\\uDC4D]/' }, - { code: 'var r = /[\\uD83D]/u' }, - { code: 'var r = /[\\uDC4D]/u' }, + { code: 'var r = /[\\uD83D]/' }, + { code: 'var r = /[\\uDC4D]/' }, + { code: 'var r = /[\\uD83D]/u' }, + { code: 'var r = /[\\uDC4D]/u' }, - { code: 'var r = /[\\u0301]/' }, - { code: 'var r = /[\\uFE0F]/' }, - { code: 'var r = /[\\u0301]/u' }, - { code: 'var r = /[\\uFE0F]/u' }, + { code: 'var r = /[\\u0301]/' }, + { code: 'var r = /[\\uFE0F]/' }, + { code: 'var r = /[\\u0301]/u' }, + { code: 'var r = /[\\uFE0F]/u' }, - { code: 'var r = /[x\\S]/u' }, - { code: 'var r = /[xa-z]/u' }, + { code: 'var r = /[x\\S]/u' }, + { code: 'var r = /[xa-z]/u' }, - { code: 'var r = /[\\u{1F3FB}]/u' }, - { code: 'var r = /[\u{1F3FB}]/u' }, + { code: 'var r = /[\\u{1F3FB}]/u' }, + { code: 'var r = /[\u{1F3FB}]/u' }, - { code: 'var r = /[🇯]/u' }, - { code: 'var r = /[🇵]/u' }, + { code: 'var r = /[🇯]/u' }, + { code: 'var r = /[🇵]/u' }, - { code: 'var r = /[\\u200D]/' }, - { code: 'var r = /[\\u200D]/u' }, + { code: 'var r = /[\\u200D]/' }, + { code: 'var r = /[\\u200D]/u' }, - // don't report and don't crash on invalid regex - { code: "var r = new RegExp('[Á] [ ');" }, - { code: "var r = RegExp('{ [Á]', 'u');" }, + // don't report and don't crash on invalid regex + { code: "var r = new RegExp('[Á] [ ');" }, + { code: "var r = RegExp('{ [Á]', 'u');" }, - // new RegExp(`^\\[Á]$`).test("[Á]") -> true - { code: 'new RegExp(`^\\\\[Á]$`).test("[Á]")' }, + // new RegExp(`^\\[Á]$`).test("[Á]") -> true + { code: 'new RegExp(`^\\\\[Á]$`).test("[Á]")' }, - { - code: "var r = new globalThis.RegExp('[Á] [ ');", - }, - { - code: "var r = globalThis.RegExp('{ [Á]', 'u');", - }, - ], - invalid: [ - { - code: 'var r = /[\\u0041\\u0301-\\u0301]/', - errors: [{ column: 17, endColumn: 23, message: combiningClass('\\u0041\\u0301') }], - }, - { - code: 'var r = /[Á]/', - errors: [{ message: combiningClass('Á') }], - }, - { - code: 'var r = new RegExp("[Á]")', - errors: [{ column: 23, endColumn: 24, message: combiningClass('Á') }], - }, - { - code: 'var r = new RegExp(`[Á]`)', - errors: [{ column: 20, endColumn: 26, message: combiningClass('Á') }], - }, - { - code: 'var r = new RegExp(String.raw`[Á]`)', - errors: [{ column: 20, endColumn: 36, message: combiningClass('Á') }], - }, - // Regexp is /\\[Á]/ corresponding to - { - code: 'var r = new RegExp(String.raw`\\\\[Á]`)', - errors: [{ column: 20, endColumn: 38, message: combiningClass('Á') }], - }, - { - code: 'var r = /[Á]/u', - errors: [{ message: combiningClass('Á') }], - }, - { - code: 'var r = /[\\u0041\\u0301]/', - errors: [{ message: combiningClass('\\u0041\\u0301') }], - }, - { - code: 'var r = /[\\u0041\\u0301]/u', - errors: [{ message: combiningClass('\\u0041\\u0301') }], - }, - { - code: 'var r = /[\\u{41}\\u{301}]/u', - errors: [{ message: combiningClass('\\u{41}\\u{301}') }], - }, - { - code: 'var r = /[❇️]/', - errors: [{ message: combiningClass('❇️') }], - }, - { - code: 'var r = /[❇️]/u', - errors: [{ message: combiningClass('❇️') }], - }, - { - code: 'var r = /[\\u2747\\uFE0F]/', - errors: [{ message: combiningClass('\\u2747\\uFE0F') }], - }, - { - code: 'var r = /[\\u2747\\uFE0F]/u', - errors: [{ message: combiningClass('\\u2747\\uFE0F') }], - }, - { - code: 'var r = /[\\u{2747}\\u{FE0F}]/u', - errors: [{ message: combiningClass('\\u{2747}\\u{FE0F}') }], - }, - { - code: String.raw`var r = new globalThis.RegExp("[❇️]", "")`, - errors: [{ message: combiningClass('❇️') }], - }, - { - code: String.raw`"cc̈d̈d".replaceAll(RegExp("[c̈d̈]"), "X")`, - errors: [{ message: combiningClass('c̈') }], - }, + { + code: "var r = new globalThis.RegExp('[Á] [ ');", + }, + { + code: "var r = globalThis.RegExp('{ [Á]', 'u');", + }, + ], + invalid: [ + { + code: 'var r = /[\\u0041\\u0301-\\u0301]/', + errors: [{ column: 17, endColumn: 23, message: combiningClass('\\u0041\\u0301') }], + }, + { + code: 'var r = /[Á]/', + errors: [{ message: combiningClass('Á') }], + }, + { + code: 'var r = new RegExp("[Á]")', + errors: [{ column: 23, endColumn: 24, message: combiningClass('Á') }], + }, + { + code: 'var r = new RegExp(`[Á]`)', + errors: [{ column: 20, endColumn: 26, message: combiningClass('Á') }], + }, + { + code: 'var r = new RegExp(String.raw`[Á]`)', + errors: [{ column: 20, endColumn: 36, message: combiningClass('Á') }], + }, + // Regexp is /\\[Á]/ corresponding to + { + code: 'var r = new RegExp(String.raw`\\\\[Á]`)', + errors: [{ column: 20, endColumn: 38, message: combiningClass('Á') }], + }, + { + code: 'var r = /[Á]/u', + errors: [{ message: combiningClass('Á') }], + }, + { + code: 'var r = /[\\u0041\\u0301]/', + errors: [{ message: combiningClass('\\u0041\\u0301') }], + }, + { + code: 'var r = /[\\u0041\\u0301]/u', + errors: [{ message: combiningClass('\\u0041\\u0301') }], + }, + { + code: 'var r = /[\\u{41}\\u{301}]/u', + errors: [{ message: combiningClass('\\u{41}\\u{301}') }], + }, + { + code: 'var r = /[❇️]/', + errors: [{ message: combiningClass('❇️') }], + }, + { + code: 'var r = /[❇️]/u', + errors: [{ message: combiningClass('❇️') }], + }, + { + code: 'var r = /[\\u2747\\uFE0F]/', + errors: [{ message: combiningClass('\\u2747\\uFE0F') }], + }, + { + code: 'var r = /[\\u2747\\uFE0F]/u', + errors: [{ message: combiningClass('\\u2747\\uFE0F') }], + }, + { + code: 'var r = /[\\u{2747}\\u{FE0F}]/u', + errors: [{ message: combiningClass('\\u{2747}\\u{FE0F}') }], + }, + { + code: String.raw`var r = new globalThis.RegExp("[❇️]", "")`, + errors: [{ message: combiningClass('❇️') }], + }, + { + code: String.raw`"cc̈d̈d".replaceAll(RegExp("[c̈d̈]"), "X")`, + errors: [{ message: combiningClass('c̈') }], + }, - // RegExp Literals. - { - code: 'var r = /[👍]/', - errors: surrogatePair('👍', 'var r = /[👍]/u', 12, 13), - }, - { - code: 'var r = /[\\uD83D\\uDC4D]/', - errors: surrogatePair('\\uD83D\\uDC4D', 'var r = /[\\uD83D\\uDC4D]/u'), - }, - { - code: 'var r = /(?<=[👍])/', - languageOptions: { ecmaVersion: 9 }, - errors: surrogatePair('👍', 'var r = /(?<=[👍])/u'), - }, - { - code: 'var r = /[👶🏻]/', - errors: surrogatePair('👶', 'var r = /[👶🏻]/u'), - }, - { - code: 'var r = /[👶🏻]/u', - errors: [{ column: 13, endColumn: 15, message: modifiedEmoji('👶🏻') }], - }, - { - code: 'var r = new RegExp("[👶🏻]", "u")', - errors: [{ column: 26, endColumn: 27, message: modifiedEmoji('👶🏻') }], - }, - { - code: 'var r = new RegExp(String.raw`[👶🏻]`, String.raw`u`)', - errors: [{ column: 20, endColumn: 38, message: modifiedEmoji('👶🏻') }], - }, - { - code: 'var r = /[\\uD83D\\uDC76\\uD83C\\uDFFB]/u', - errors: [{ message: modifiedEmoji('\\uD83D\\uDC76\\uD83C\\uDFFB') }], - }, - { - code: 'var r = /[\\u{1F476}\\u{1F3FB}]/u', - errors: [{ message: modifiedEmoji('\\u{1F476}\\u{1F3FB}') }], - }, - { - code: 'var r = /[🇯🇵]/', - errors: surrogatePair('🇯', 'var r = /[🇯🇵]/u'), - }, - { - code: 'var r = /[🇯🇵]/i', - errors: surrogatePair('🇯', 'var r = /[🇯🇵]/iu'), - }, - { - code: 'var r = /[🇯🇵]/u', - errors: [{ column: 13, endColumn: 15, message: regionalIndicator('🇯🇵') }], - }, - { - code: 'var r = new RegExp("[🇯🇵]", "u")', - errors: [{ column: 26, endColumn: 27, message: regionalIndicator('🇯🇵') }], - }, - { - code: 'var r = new RegExp(`[🇯🇵]`, `u`)', - errors: [{ column: 20, endColumn: 28, message: regionalIndicator('🇯🇵') }], - }, - { - code: 'var r = new RegExp(String.raw`[🇯🇵]`, `u`)', - errors: [{ column: 20, endColumn: 38, message: regionalIndicator('🇯🇵') }], - }, - { - code: 'var r = /[\\uD83C\\uDDEF\\uD83C\\uDDF5]/u', - errors: [{ message: regionalIndicator('\\uD83C\\uDDEF\\uD83C\\uDDF5') }], - }, - { - code: 'var r = /[\\u{1F1EF}\\u{1F1F5}]/u', - errors: [{ message: regionalIndicator('\\u{1F1EF}\\u{1F1F5}') }], - }, - { - code: 'var r = /[👨‍👩‍👦]/', - errors: surrogatePair('👨', 'var r = /[👨‍👩‍👦]/u'), - }, - { - code: 'var r = /[👨‍👩‍👦]/u', - errors: [{ column: 11, endColumn: 13, message: zwj }], - }, - { - code: 'var r = new RegExp("[👨‍👩‍👦]", "u")', - errors: [{ column: 22, endColumn: 25, message: zwj }], - }, - { - code: 'var r = new RegExp(`[👨‍👩‍👦]`, `u`)', - errors: [{ column: 20, endColumn: 32, message: zwj }], - }, - { - code: 'var r = new RegExp(String.raw`[👨‍👩‍👦]`, String.raw`u`)', - errors: [{ column: 20, endColumn: 42, message: zwj }], - }, - { - code: 'var r = /[\\uD83D\\uDC68\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC66]/u', - errors: [{ message: zwj }], - }, - { - code: 'var r = /[\\u{1F468}\\u{200D}\\u{1F469}\\u{200D}\\u{1F466}]/u', - errors: [{ message: zwj }], - }, + // RegExp Literals. + { + code: 'var r = /[👍]/', + errors: surrogatePair('👍', 'var r = /[👍]/u', 12, 13), + }, + { + code: 'var r = /[\\uD83D\\uDC4D]/', + errors: surrogatePair('\\uD83D\\uDC4D', 'var r = /[\\uD83D\\uDC4D]/u'), + }, + { + code: 'var r = /(?<=[👍])/', + languageOptions: { ecmaVersion: 9 }, + errors: surrogatePair('👍', 'var r = /(?<=[👍])/u'), + }, + { + code: 'var r = /[👶🏻]/', + errors: surrogatePair('👶', 'var r = /[👶🏻]/u'), + }, + { + code: 'var r = /[👶🏻]/u', + errors: [{ column: 13, endColumn: 15, message: modifiedEmoji('👶🏻') }], + }, + { + code: 'var r = new RegExp("[👶🏻]", "u")', + errors: [{ column: 26, endColumn: 27, message: modifiedEmoji('👶🏻') }], + }, + { + code: 'var r = new RegExp(String.raw`[👶🏻]`, String.raw`u`)', + errors: [{ column: 20, endColumn: 38, message: modifiedEmoji('👶🏻') }], + }, + { + code: 'var r = /[\\uD83D\\uDC76\\uD83C\\uDFFB]/u', + errors: [{ message: modifiedEmoji('\\uD83D\\uDC76\\uD83C\\uDFFB') }], + }, + { + code: 'var r = /[\\u{1F476}\\u{1F3FB}]/u', + errors: [{ message: modifiedEmoji('\\u{1F476}\\u{1F3FB}') }], + }, + { + code: 'var r = /[🇯🇵]/', + errors: surrogatePair('🇯', 'var r = /[🇯🇵]/u'), + }, + { + code: 'var r = /[🇯🇵]/i', + errors: surrogatePair('🇯', 'var r = /[🇯🇵]/iu'), + }, + { + code: 'var r = /[🇯🇵]/u', + errors: [{ column: 13, endColumn: 15, message: regionalIndicator('🇯🇵') }], + }, + { + code: 'var r = new RegExp("[🇯🇵]", "u")', + errors: [{ column: 26, endColumn: 27, message: regionalIndicator('🇯🇵') }], + }, + { + code: 'var r = new RegExp(`[🇯🇵]`, `u`)', + errors: [{ column: 20, endColumn: 28, message: regionalIndicator('🇯🇵') }], + }, + { + code: 'var r = new RegExp(String.raw`[🇯🇵]`, `u`)', + errors: [{ column: 20, endColumn: 38, message: regionalIndicator('🇯🇵') }], + }, + { + code: 'var r = /[\\uD83C\\uDDEF\\uD83C\\uDDF5]/u', + errors: [{ message: regionalIndicator('\\uD83C\\uDDEF\\uD83C\\uDDF5') }], + }, + { + code: 'var r = /[\\u{1F1EF}\\u{1F1F5}]/u', + errors: [{ message: regionalIndicator('\\u{1F1EF}\\u{1F1F5}') }], + }, + { + code: 'var r = /[👨‍👩‍👦]/', + errors: surrogatePair('👨', 'var r = /[👨‍👩‍👦]/u'), + }, + { + code: 'var r = /[👨‍👩‍👦]/u', + errors: [{ column: 11, endColumn: 13, message: zwj }], + }, + { + code: 'var r = new RegExp("[👨‍👩‍👦]", "u")', + errors: [{ column: 22, endColumn: 25, message: zwj }], + }, + { + code: 'var r = new RegExp(`[👨‍👩‍👦]`, `u`)', + errors: [{ column: 20, endColumn: 32, message: zwj }], + }, + { + code: 'var r = new RegExp(String.raw`[👨‍👩‍👦]`, String.raw`u`)', + errors: [{ column: 20, endColumn: 42, message: zwj }], + }, + { + code: 'var r = /[\\uD83D\\uDC68\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC66]/u', + errors: [{ message: zwj }], + }, + { + code: 'var r = /[\\u{1F468}\\u{200D}\\u{1F469}\\u{200D}\\u{1F466}]/u', + errors: [{ message: zwj }], + }, - // RegExp constructors. - { - code: 'var r = new RegExp("[👍]")', - errors: surrogatePair('👍', 'var r = new RegExp("[👍]", "u")', 24, 25), - }, - { - code: 'var r = new RegExp(`[👍]`)', - errors: surrogatePair('👍', 'var r = new RegExp(`[👍]`, "u")', 20, 26), - }, - { - code: 'var r = new RegExp(String.raw`[👍]`)', - errors: surrogatePair('👍', 'var r = new RegExp(String.raw`[👍]`, "u")', 20, 36), - }, - { - code: 'var r = new RegExp("[👍]", "")', - errors: surrogatePair('👍', 'var r = new RegExp("[👍]", "u")'), - }, - { - code: 'var r = new RegExp(`[👍]`, ``)', - errors: surrogatePair('👍', 'var r = new RegExp(`[👍]`, `u`)'), - }, - { - code: 'var r = new RegExp(String.raw`[👍]`, String.raw``)', - errors: surrogatePair('👍', 'var r = new RegExp(String.raw`[👍]`, String.raw`u`)'), - }, - { - code: 'var r = new RegExp("[👍]", "i")', - errors: surrogatePair('👍', 'var r = new RegExp("[👍]", "iu")'), - }, - { - code: 'var r = new RegExp(`[👍]`, `i`)', - errors: surrogatePair('👍', 'var r = new RegExp(`[👍]`, `iu`)'), - }, - { - code: 'var r = new RegExp(String.raw`[👍]`, String.raw`i`)', - errors: surrogatePair('👍', 'var r = new RegExp(String.raw`[👍]`, String.raw`iu`)'), - }, - { - code: String.raw`var r = new RegExp("[\\uD83D\\uDC4D]", "")`, - errors: surrogatePair( - '\\uD83D\\uDC4D', - String.raw`var r = new RegExp("[\\uD83D\\uDC4D]", "u")`, - ), - }, - { - code: String.raw`var r = new RegExp("/(?<=[👍])", "")`, - languageOptions: { ecmaVersion: 9 }, - errors: surrogatePair('👍', String.raw`var r = new RegExp("/(?<=[👍])", "u")`), - }, - { - code: String.raw`var r = new RegExp("/(?<=[👍])", "")`, - languageOptions: { ecmaVersion: 2018 }, - errors: surrogatePair('👍', String.raw`var r = new RegExp("/(?<=[👍])", "u")`), - }, - { - code: String.raw`var r = new RegExp("[👶🏻]", "")`, - errors: surrogatePair('👶', String.raw`var r = new RegExp("[👶🏻]", "u")`), - }, - { - code: String.raw`var r = new RegExp("[\\uD83D\\uDC76\\uD83C\\uDFFB]", "u")`, - errors: [{ message: modifiedEmoji('\\uD83D\\uDC76\\uD83C\\uDFFB') }], - }, - { - code: String.raw`var r = new RegExp("[\\u{1F476}\\u{1F3FB}]", "u")`, - errors: [{ message: modifiedEmoji('\\u{1F476}\\u{1F3FB}') }], - }, - { - code: String.raw`var r = new RegExp("[🇯🇵]", "")`, - errors: surrogatePair('🇯', String.raw`var r = new RegExp("[🇯🇵]", "u")`), - }, - { - code: String.raw`var r = new RegExp("[🇯🇵]", "i")`, - errors: surrogatePair('🇯', String.raw`var r = new RegExp("[🇯🇵]", "iu")`), - }, - { - code: "var r = new RegExp('[🇯🇵]', `i`)", - errors: surrogatePair('🇯', "var r = new RegExp('[🇯🇵]', `iu`)"), - }, - { - code: String.raw`var r = new RegExp("[🇯🇵]")`, - errors: surrogatePair('🇯', String.raw`var r = new RegExp("[🇯🇵]", "u")`), - }, - { - code: String.raw`var r = new RegExp(("[🇯🇵]"))`, - errors: surrogatePair('🇯', String.raw`var r = new RegExp(("[🇯🇵]"), "u")`), - }, - { - code: String.raw`var r = new RegExp((("[🇯🇵]")))`, - errors: surrogatePair('🇯', String.raw`var r = new RegExp((("[🇯🇵]")), "u")`), - }, - { - code: String.raw`var r = new RegExp("[\\uD83C\\uDDEF\\uD83C\\uDDF5]", "u")`, - errors: [{ message: regionalIndicator('\\uD83C\\uDDEF\\uD83C\\uDDF5') }], - }, - { - code: String.raw`var r = new RegExp("[\\u{1F1EF}\\u{1F1F5}]", "u")`, - errors: [{ message: regionalIndicator('\\u{1F1EF}\\u{1F1F5}') }], - }, - { - code: String.raw`var r = new RegExp("[👨‍👩‍👦]", "")`, - errors: surrogatePair('👨', String.raw`var r = new RegExp("[👨‍👩‍👦]", "u")`), - }, - { - code: String.raw`var r = new RegExp("[\\uD83D\\uDC68\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC66]", "u")`, - errors: [{ message: zwj }], - }, - { - code: String.raw`var r = new RegExp("[\\u{1F468}\\u{200D}\\u{1F469}\\u{200D}\\u{1F466}]", "u")`, - errors: [{ message: zwj }], - }, - { - code: String.raw`var r = new globalThis.RegExp("[👶🏻]", "u")`, - errors: [{ message: modifiedEmoji('👶🏻') }], - }, - { - code: String.raw`var r = new globalThis.RegExp("[🇯🇵]", "")`, - errors: surrogatePair('🇯', String.raw`var r = new globalThis.RegExp("[🇯🇵]", "u")`), - }, - { - code: String.raw`var r = new globalThis.RegExp("[\\u{1F468}\\u{200D}\\u{1F469}\\u{200D}\\u{1F466}]", "u")`, - errors: [{ message: zwj }], - }, - { - code: 'var r = new RegExp("[" + "👍" + "]")', - errors: surrogatePair('👍', 'var r = new RegExp("[" + "👍" + "]", "u")'), - }, - { - code: 'const p = "[" + "👍" + "]", r = new RegExp(p)', - errors: surrogatePair('👍', 'const p = "[" + "👍" + "]", r = new RegExp(p, "u")'), - }, - { - code: 'const c = "👍", p = "[" + c + "]", r = new RegExp(p)', - errors: surrogatePair('👍', 'const c = "👍", p = "[" + c + "]", r = new RegExp(p, "u")'), - }, - ], + // RegExp constructors. + { + code: 'var r = new RegExp("[👍]")', + errors: surrogatePair('👍', 'var r = new RegExp("[👍]", "u")', 24, 25), + }, + { + code: 'var r = new RegExp(`[👍]`)', + errors: surrogatePair('👍', 'var r = new RegExp(`[👍]`, "u")', 20, 26), + }, + { + code: 'var r = new RegExp(String.raw`[👍]`)', + errors: surrogatePair('👍', 'var r = new RegExp(String.raw`[👍]`, "u")', 20, 36), + }, + { + code: 'var r = new RegExp("[👍]", "")', + errors: surrogatePair('👍', 'var r = new RegExp("[👍]", "u")'), + }, + { + code: 'var r = new RegExp(`[👍]`, ``)', + errors: surrogatePair('👍', 'var r = new RegExp(`[👍]`, `u`)'), + }, + { + code: 'var r = new RegExp(String.raw`[👍]`, String.raw``)', + errors: surrogatePair('👍', 'var r = new RegExp(String.raw`[👍]`, String.raw`u`)'), + }, + { + code: 'var r = new RegExp("[👍]", "i")', + errors: surrogatePair('👍', 'var r = new RegExp("[👍]", "iu")'), + }, + { + code: 'var r = new RegExp(`[👍]`, `i`)', + errors: surrogatePair('👍', 'var r = new RegExp(`[👍]`, `iu`)'), + }, + { + code: 'var r = new RegExp(String.raw`[👍]`, String.raw`i`)', + errors: surrogatePair('👍', 'var r = new RegExp(String.raw`[👍]`, String.raw`iu`)'), + }, + { + code: String.raw`var r = new RegExp("[\\uD83D\\uDC4D]", "")`, + errors: surrogatePair( + '\\uD83D\\uDC4D', + String.raw`var r = new RegExp("[\\uD83D\\uDC4D]", "u")`, + ), + }, + { + code: String.raw`var r = new RegExp("/(?<=[👍])", "")`, + languageOptions: { ecmaVersion: 9 }, + errors: surrogatePair('👍', String.raw`var r = new RegExp("/(?<=[👍])", "u")`), + }, + { + code: String.raw`var r = new RegExp("/(?<=[👍])", "")`, + languageOptions: { ecmaVersion: 2018 }, + errors: surrogatePair('👍', String.raw`var r = new RegExp("/(?<=[👍])", "u")`), + }, + { + code: String.raw`var r = new RegExp("[👶🏻]", "")`, + errors: surrogatePair('👶', String.raw`var r = new RegExp("[👶🏻]", "u")`), + }, + { + code: String.raw`var r = new RegExp("[\\uD83D\\uDC76\\uD83C\\uDFFB]", "u")`, + errors: [{ message: modifiedEmoji('\\uD83D\\uDC76\\uD83C\\uDFFB') }], + }, + { + code: String.raw`var r = new RegExp("[\\u{1F476}\\u{1F3FB}]", "u")`, + errors: [{ message: modifiedEmoji('\\u{1F476}\\u{1F3FB}') }], + }, + { + code: String.raw`var r = new RegExp("[🇯🇵]", "")`, + errors: surrogatePair('🇯', String.raw`var r = new RegExp("[🇯🇵]", "u")`), + }, + { + code: String.raw`var r = new RegExp("[🇯🇵]", "i")`, + errors: surrogatePair('🇯', String.raw`var r = new RegExp("[🇯🇵]", "iu")`), + }, + { + code: "var r = new RegExp('[🇯🇵]', `i`)", + errors: surrogatePair('🇯', "var r = new RegExp('[🇯🇵]', `iu`)"), + }, + { + code: String.raw`var r = new RegExp("[🇯🇵]")`, + errors: surrogatePair('🇯', String.raw`var r = new RegExp("[🇯🇵]", "u")`), + }, + { + code: String.raw`var r = new RegExp(("[🇯🇵]"))`, + errors: surrogatePair('🇯', String.raw`var r = new RegExp(("[🇯🇵]"), "u")`), + }, + { + code: String.raw`var r = new RegExp((("[🇯🇵]")))`, + errors: surrogatePair('🇯', String.raw`var r = new RegExp((("[🇯🇵]")), "u")`), + }, + { + code: String.raw`var r = new RegExp("[\\uD83C\\uDDEF\\uD83C\\uDDF5]", "u")`, + errors: [{ message: regionalIndicator('\\uD83C\\uDDEF\\uD83C\\uDDF5') }], + }, + { + code: String.raw`var r = new RegExp("[\\u{1F1EF}\\u{1F1F5}]", "u")`, + errors: [{ message: regionalIndicator('\\u{1F1EF}\\u{1F1F5}') }], + }, + { + code: String.raw`var r = new RegExp("[👨‍👩‍👦]", "")`, + errors: surrogatePair('👨', String.raw`var r = new RegExp("[👨‍👩‍👦]", "u")`), + }, + { + code: String.raw`var r = new RegExp("[\\uD83D\\uDC68\\u200D\\uD83D\\uDC69\\u200D\\uD83D\\uDC66]", "u")`, + errors: [{ message: zwj }], + }, + { + code: String.raw`var r = new RegExp("[\\u{1F468}\\u{200D}\\u{1F469}\\u{200D}\\u{1F466}]", "u")`, + errors: [{ message: zwj }], + }, + { + code: String.raw`var r = new globalThis.RegExp("[👶🏻]", "u")`, + errors: [{ message: modifiedEmoji('👶🏻') }], + }, + { + code: String.raw`var r = new globalThis.RegExp("[🇯🇵]", "")`, + errors: surrogatePair('🇯', String.raw`var r = new globalThis.RegExp("[🇯🇵]", "u")`), + }, + { + code: String.raw`var r = new globalThis.RegExp("[\\u{1F468}\\u{200D}\\u{1F469}\\u{200D}\\u{1F466}]", "u")`, + errors: [{ message: zwj }], + }, + { + code: 'var r = new RegExp("[" + "👍" + "]")', + errors: surrogatePair('👍', 'var r = new RegExp("[" + "👍" + "]", "u")'), + }, + { + code: 'const p = "[" + "👍" + "]", r = new RegExp(p)', + errors: surrogatePair('👍', 'const p = "[" + "👍" + "]", r = new RegExp(p, "u")'), + }, + { + code: 'const c = "👍", p = "[" + c + "]", r = new RegExp(p)', + errors: surrogatePair('👍', 'const c = "👍", p = "[" + c + "]", r = new RegExp(p, "u")'), + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S5869/unit.test.ts b/packages/jsts/src/rules/S5869/unit.test.ts index d8de0ecece..3ac8c543c1 100644 --- a/packages/jsts/src/rules/S5869/unit.test.ts +++ b/packages/jsts/src/rules/S5869/unit.test.ts @@ -16,225 +16,227 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5869', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Duplicated characters in character classes', rule, { - valid: [ - { - code: `/a-z\\d/`, - }, - { - code: `/[0-9][0-9]?/`, - }, - { - code: `/[xX]/`, - }, - { - code: `/[\\s\\S]/`, - }, - { - code: `/[\\s\\S]/u`, - }, - { - code: `/[\\S\\u0085\\u2028\\u2029]/u`, - }, - { - code: `/[\\d\\D]/`, - }, - { - code: `/[\\d\\D]/u`, - }, - { - code: `/[\\w\\W]/`, - }, - { - code: `/[\\w\\W]/u`, - }, - { - code: `/[\\wä]/`, - }, - { - code: `/[äÄ]/i`, - }, - { - code: `/[Ä-Üä]/i`, - }, - { - code: `/[äÄ]/u`, - }, - { - code: `/[xX]/u`, - }, - { - code: `/[ab-z]/`, - }, - { - code: `/[a-Öö]/i`, - }, - { - code: `/[\\x00\\x01]]/`, - }, - { - code: `/[\\x00-\\x01\\x02-\\x03]]/`, - }, - { - code: `/[\\wä]"/u`, // False negative because we don't support Unicode characters in \\w and \\W - }, - { - code: `/[A-_d-{]/i`, // FN because we ignore case insensitivity unless both ends of the ranges are letters - }, - { - code: `/[A-z_]/i`, // FN because A-z gets misinterpreted as A-Za-z due to the way we handle case insensitivity - }, - { - code: `/[\\p{IsLatin}x]/`, // FN because we don't support \p at the moment - }, - ], - invalid: [ - { - code: `/[0-99]/`, - errors: [ - { - message: JSON.stringify({ - message: 'Remove duplicates in this character class.', - secondaryLocations: [ - { message: 'Additional duplicate', column: 5, line: 1, endColumn: 6, endLine: 1 }, - ], - }), - line: 1, - endLine: 1, - column: 3, - endColumn: 6, - }, - ], - options: ['sonar-runtime'], - }, - { - code: `/[90-9]/`, - errors: 1, - }, - { - code: `/[0-73-9]/`, - errors: 1, - }, - { - code: `/[0-93-57]/`, - errors: 1, - }, - { - code: `/[4-92-68]/`, - errors: 1, - }, - { - code: `/[0-33-9]/`, - errors: 1, - }, - { - code: `/[0-70-9]/`, - errors: 1, - }, - { - code: `/[3-90-7]/`, - errors: 1, - }, - { - code: `/[3-50-9]/`, - errors: 1, - }, - { - code: `/[xxx]/`, - errors: 1, - }, - { - code: `/[A-z_]/`, - errors: 1, - }, - { - code: `/[A-Za-z]/i`, - errors: 1, - }, - { - code: `/[A-_d]/i`, - errors: 1, - }, - { - code: `/[Ä-Üä]/iu`, - errors: 1, - }, - { - code: `/[a-Öö]/iu`, - errors: 1, - }, - { - code: `/[ ]/`, - errors: 1, - }, - { - code: `/[ ]/i`, - errors: 1, - }, - { - code: `/[ ]iu/`, - errors: 1, - }, - { - code: `/[A-_D]/i`, - errors: 1, - }, - { - code: `/[A-_D]iu/`, - errors: 1, - }, - { - code: `/[xX]/i`, - errors: 1, - }, - { - code: `/[xX]/iu`, - errors: 1, - }, - { - code: `/[äÄ]/iu`, - errors: 1, - }, - { - code: `/[\\\"\\\".]"/`, - errors: 1, - }, - { - code: `/[\\Qxx\\E]/`, - errors: 1, - }, - { - code: `/[\\s\\Sx]/`, - errors: 1, - }, - { - code: `/[\\s\\Sx]/u`, - errors: 1, - }, - { - code: `/[\\w\\d]"/`, - errors: 1, - }, - { - code: `/[\\wa]/`, - errors: 1, - }, - { - code: `/[\\d1]/`, - errors: 1, - }, - { - code: `/[\\d1-3]/`, - errors: 1, - }, - { - code: `/[\\wa]/u`, - errors: 1, - }, - ], + it('S5869', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Duplicated characters in character classes', rule, { + valid: [ + { + code: `/a-z\\d/`, + }, + { + code: `/[0-9][0-9]?/`, + }, + { + code: `/[xX]/`, + }, + { + code: `/[\\s\\S]/`, + }, + { + code: `/[\\s\\S]/u`, + }, + { + code: `/[\\S\\u0085\\u2028\\u2029]/u`, + }, + { + code: `/[\\d\\D]/`, + }, + { + code: `/[\\d\\D]/u`, + }, + { + code: `/[\\w\\W]/`, + }, + { + code: `/[\\w\\W]/u`, + }, + { + code: `/[\\wä]/`, + }, + { + code: `/[äÄ]/i`, + }, + { + code: `/[Ä-Üä]/i`, + }, + { + code: `/[äÄ]/u`, + }, + { + code: `/[xX]/u`, + }, + { + code: `/[ab-z]/`, + }, + { + code: `/[a-Öö]/i`, + }, + { + code: `/[\\x00\\x01]]/`, + }, + { + code: `/[\\x00-\\x01\\x02-\\x03]]/`, + }, + { + code: `/[\\wä]"/u`, // False negative because we don't support Unicode characters in \\w and \\W + }, + { + code: `/[A-_d-{]/i`, // FN because we ignore case insensitivity unless both ends of the ranges are letters + }, + { + code: `/[A-z_]/i`, // FN because A-z gets misinterpreted as A-Za-z due to the way we handle case insensitivity + }, + { + code: `/[\\p{IsLatin}x]/`, // FN because we don't support \p at the moment + }, + ], + invalid: [ + { + code: `/[0-99]/`, + errors: [ + { + message: JSON.stringify({ + message: 'Remove duplicates in this character class.', + secondaryLocations: [ + { message: 'Additional duplicate', column: 5, line: 1, endColumn: 6, endLine: 1 }, + ], + }), + line: 1, + endLine: 1, + column: 3, + endColumn: 6, + }, + ], + options: ['sonar-runtime'], + }, + { + code: `/[90-9]/`, + errors: 1, + }, + { + code: `/[0-73-9]/`, + errors: 1, + }, + { + code: `/[0-93-57]/`, + errors: 1, + }, + { + code: `/[4-92-68]/`, + errors: 1, + }, + { + code: `/[0-33-9]/`, + errors: 1, + }, + { + code: `/[0-70-9]/`, + errors: 1, + }, + { + code: `/[3-90-7]/`, + errors: 1, + }, + { + code: `/[3-50-9]/`, + errors: 1, + }, + { + code: `/[xxx]/`, + errors: 1, + }, + { + code: `/[A-z_]/`, + errors: 1, + }, + { + code: `/[A-Za-z]/i`, + errors: 1, + }, + { + code: `/[A-_d]/i`, + errors: 1, + }, + { + code: `/[Ä-Üä]/iu`, + errors: 1, + }, + { + code: `/[a-Öö]/iu`, + errors: 1, + }, + { + code: `/[ ]/`, + errors: 1, + }, + { + code: `/[ ]/i`, + errors: 1, + }, + { + code: `/[ ]iu/`, + errors: 1, + }, + { + code: `/[A-_D]/i`, + errors: 1, + }, + { + code: `/[A-_D]iu/`, + errors: 1, + }, + { + code: `/[xX]/i`, + errors: 1, + }, + { + code: `/[xX]/iu`, + errors: 1, + }, + { + code: `/[äÄ]/iu`, + errors: 1, + }, + { + code: `/[\\\"\\\".]"/`, + errors: 1, + }, + { + code: `/[\\Qxx\\E]/`, + errors: 1, + }, + { + code: `/[\\s\\Sx]/`, + errors: 1, + }, + { + code: `/[\\s\\Sx]/u`, + errors: 1, + }, + { + code: `/[\\w\\d]"/`, + errors: 1, + }, + { + code: `/[\\wa]/`, + errors: 1, + }, + { + code: `/[\\d1]/`, + errors: 1, + }, + { + code: `/[\\d1-3]/`, + errors: 1, + }, + { + code: `/[\\wa]/u`, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S5876/unit.test.ts b/packages/jsts/src/rules/S5876/unit.test.ts index 920f81081a..b1b4ed81c6 100644 --- a/packages/jsts/src/rules/S5876/unit.test.ts +++ b/packages/jsts/src/rules/S5876/unit.test.ts @@ -16,17 +16,18 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S5876', () => { - const ruleTester = new RuleTester(); - ruleTester.run( - 'Create a new session during user authentication to prevent session fixation attacks.', - rule, - { - valid: [ - { - code: ` + it('S5876', () => { + const ruleTester = new RuleTester(); + ruleTester.run( + 'Create a new session during user authentication to prevent session fixation attacks.', + rule, + { + valid: [ + { + code: ` var passport = require('passport'); app.post('/login', @@ -39,21 +40,21 @@ describe('S5876', () => { }); console.log('coverage'); });`, - }, - { - code: ` + }, + { + code: ` var passport = require('passport'); passport.authenticate('local', { failureRedirect: '/login' }); `, - }, - { - code: ` + }, + { + code: ` var passport = require('passport'); app.post('/login', passport.authenticate('local', { failureRedirect: '/login' }), foo); `, - }, - { - code: ` + }, + { + code: ` var passport = require('passport'); app.post('/api/login', passport.authenticate('local', { session: false }), // Compliant - no session @@ -61,11 +62,11 @@ describe('S5876', () => { res.redirect('/'); }); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` var passport = require('passport'); app.post('/login', @@ -74,19 +75,19 @@ describe('S5876', () => { // Sensitive - no session.regenerate after login res.redirect('/'); });`, - errors: [ - { - message: - 'Create a new session during user authentication to prevent session fixation attacks.', - line: 6, - column: 7, - endLine: 9, - endColumn: 8, - }, - ], - }, - { - code: ` + errors: [ + { + message: + 'Create a new session during user authentication to prevent session fixation attacks.', + line: 6, + column: 7, + endLine: 9, + endColumn: 8, + }, + ], + }, + { + code: ` var passport = require('passport'); app.post('/api/login', passport.authenticate('local', { session: true }), @@ -94,10 +95,10 @@ describe('S5876', () => { res.redirect('/'); }); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` var passport = require('passport'); app.post('/api/login', passport.authenticate('local', foo()), // could be FP if foo() sets session to false @@ -105,9 +106,10 @@ describe('S5876', () => { res.redirect('/'); }); `, - errors: 1, - }, - ], - }, - ); + errors: 1, + }, + ], + }, + ); + }); }); diff --git a/packages/jsts/src/rules/S6019/unit.test.ts b/packages/jsts/src/rules/S6019/unit.test.ts index 21425d1ac1..bb1822a44e 100644 --- a/packages/jsts/src/rules/S6019/unit.test.ts +++ b/packages/jsts/src/rules/S6019/unit.test.ts @@ -16,86 +16,88 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6019', () => { - const ruleTesterTs = new RuleTester(); - ruleTesterTs.run('Reluctant quantifiers followed by an optional', rule, { - valid: [ - { - code: ` + it('S6019', () => { + const ruleTesterTs = new RuleTester(); + ruleTesterTs.run('Reluctant quantifiers followed by an optional', rule, { + valid: [ + { + code: ` /a*?x/; /a*?[abc]/; /|x|a*x/; `, - }, - ], - invalid: [ - { - code: `/a*?$/`, - errors: [ - { - message: `Remove the '?' from this unnecessarily reluctant quantifier.`, - line: 1, - column: 2, - endLine: 1, - endColumn: 5, - }, - ], - }, - { - code: `/a*?x?/`, - errors: [ - { - message: `Fix this reluctant quantifier that will only ever match 0 repetitions.`, - }, - ], - }, - { - code: `/a*?x*/`, - errors: [ - { - message: `Fix this reluctant quantifier that will only ever match 0 repetitions.`, - }, - ], - }, - { - code: `/a{5,25}?/`, - errors: [ - { - message: `Fix this reluctant quantifier that will only ever match 5 repetitions.`, - }, - ], - }, - { - code: `/a*?|a*?x?/`, - errors: [ - { - message: `Fix this reluctant quantifier that will only ever match 0 repetitions.`, - column: 2, - }, - { - message: `Fix this reluctant quantifier that will only ever match 0 repetitions.`, - column: 6, - }, - ], - }, - { - code: `/a+?(x)?/`, - errors: [ - { - message: `Fix this reluctant quantifier that will only ever match 1 repetition.`, - }, - ], - }, - { - code: `/foo_a+?/`, - errors: [ - { - message: `Fix this reluctant quantifier that will only ever match 1 repetition.`, - }, - ], - }, - ], + }, + ], + invalid: [ + { + code: `/a*?$/`, + errors: [ + { + message: `Remove the '?' from this unnecessarily reluctant quantifier.`, + line: 1, + column: 2, + endLine: 1, + endColumn: 5, + }, + ], + }, + { + code: `/a*?x?/`, + errors: [ + { + message: `Fix this reluctant quantifier that will only ever match 0 repetitions.`, + }, + ], + }, + { + code: `/a*?x*/`, + errors: [ + { + message: `Fix this reluctant quantifier that will only ever match 0 repetitions.`, + }, + ], + }, + { + code: `/a{5,25}?/`, + errors: [ + { + message: `Fix this reluctant quantifier that will only ever match 5 repetitions.`, + }, + ], + }, + { + code: `/a*?|a*?x?/`, + errors: [ + { + message: `Fix this reluctant quantifier that will only ever match 0 repetitions.`, + column: 2, + }, + { + message: `Fix this reluctant quantifier that will only ever match 0 repetitions.`, + column: 6, + }, + ], + }, + { + code: `/a+?(x)?/`, + errors: [ + { + message: `Fix this reluctant quantifier that will only ever match 1 repetition.`, + }, + ], + }, + { + code: `/foo_a+?/`, + errors: [ + { + message: `Fix this reluctant quantifier that will only ever match 1 repetition.`, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S6035/unit.test.ts b/packages/jsts/src/rules/S6035/unit.test.ts index 6b200ade9a..43ba5f450d 100644 --- a/packages/jsts/src/rules/S6035/unit.test.ts +++ b/packages/jsts/src/rules/S6035/unit.test.ts @@ -16,98 +16,100 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6035', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Single-character alternation', rule, { - valid: [ - { - code: `const str = 'abc123';`, - }, - { - code: `const str = /[abc]/;`, - }, - { - code: `const re = /ab|cd/;`, - }, - { - code: `const re = /a|\\b|c/;`, - }, - { - code: `const re = /^|$/;`, - }, - { - code: `const re = /|/;`, - }, - { - code: `/(s)*/`, - }, - ], - invalid: [ - { - code: ` + it('S6035', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Single-character alternation', rule, { + valid: [ + { + code: `const str = 'abc123';`, + }, + { + code: `const str = /[abc]/;`, + }, + { + code: `const re = /ab|cd/;`, + }, + { + code: `const re = /a|\\b|c/;`, + }, + { + code: `const re = /^|$/;`, + }, + { + code: `const re = /|/;`, + }, + { + code: `/(s)*/`, + }, + ], + invalid: [ + { + code: ` const re = /a|b|c/; //^^^^^^^ `, - errors: [ - { - message: 'Replace this alternation with a character class.', - line: 2, - endLine: 2, - column: 23, - endColumn: 28, - }, - ], - }, - { - code: `const re = /a|(b|c)/;`, - errors: [ - { - message: 'Replace this alternation with a character class.', - line: 1, - endLine: 1, - column: 15, - endColumn: 20, - }, - ], - }, - { - code: `const re = /abcd|(e|f)gh/;`, - errors: 1, - }, - { - code: `const re = /(a|b|c)*/;`, - errors: 1, - }, - { - code: `const re = /(?:a|b)/;`, - errors: 1, - }, - { - code: `const re = /a(?=b|c)/;`, - errors: 1, - }, - { - code: `const re = /a(?!b|c)/;`, - errors: 1, - }, - { - code: `const re = /(?<=a|b)c/;`, - errors: 1, - }, - { - code: `const re = /(? { - const ruleTester = new RuleTester(); - ruleTester.run('Assertions should not be given twice the same argument', rule, { - valid: [ - { - code: `expect(foo).to.not.throw(ReferenceError);`, - }, - ], - invalid: [ - { - code: ` + it('S6092', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Assertions should not be given twice the same argument', rule, { + valid: [ + { + code: `expect(foo).to.not.throw(ReferenceError);`, + }, + ], + invalid: [ + { + code: ` const chai = require('chai'); expect(foo).to.not.throw(ReferenceError);`, - errors: [ - { - message: 'Refactor this uncertain assertion; it can succeed for multiple reasons.', - line: 3, - }, - ], - }, - ], + errors: [ + { + message: 'Refactor this uncertain assertion; it can succeed for multiple reasons.', + line: 3, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S6268/unit.test.ts b/packages/jsts/src/rules/S6268/unit.test.ts index 57954847a1..87b18d110b 100644 --- a/packages/jsts/src/rules/S6268/unit.test.ts +++ b/packages/jsts/src/rules/S6268/unit.test.ts @@ -16,14 +16,15 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6268', () => { - const ruleTesterTs = new RuleTester(); - ruleTesterTs.run('', rule, { - valid: [ - { - code: ` + it('S6268', () => { + const ruleTesterTs = new RuleTester(); + ruleTesterTs.run('', rule, { + valid: [ + { + code: ` // without object bypassSecurityTrustHtml(foo); @@ -41,43 +42,44 @@ describe('S6268', () => { sanitizer.bypassSecurityTrustHtml("input"); sanitizer.bypassSecurityTrustHtml(\`input\`); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` sanitizer.bypassSecurityTrustHtml(value); sanitizer.bypassSecurityTrustStyle(value); sanitizer.bypassSecurityTrustScript(value); sanitizer.bypassSecurityTrustUrl(value); sanitizer.bypassSecurityTrustResourceUrl(value); `, - errors: 5, - }, - { - code: ` + errors: 5, + }, + { + code: ` whatever().bypassSecurityTrustHtml(whateverElse()); `, - errors: [ - { - message: 'Make sure disabling Angular built-in sanitization is safe here.', - line: 2, - column: 18, - endLine: 2, - endColumn: 41, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Make sure disabling Angular built-in sanitization is safe here.', + line: 2, + column: 18, + endLine: 2, + endColumn: 41, + }, + ], + }, + { + code: ` sanitizer.bypassSecurityTrustHtml(\`\${whatever()}\`); `, - errors: [ - { - message: 'Make sure disabling Angular built-in sanitization is safe here.', - }, - ], - }, - ], + errors: [ + { + message: 'Make sure disabling Angular built-in sanitization is safe here.', + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S6299/unit.test.ts b/packages/jsts/src/rules/S6299/unit.test.ts index ea8b49e061..b6f80d4651 100644 --- a/packages/jsts/src/rules/S6299/unit.test.ts +++ b/packages/jsts/src/rules/S6299/unit.test.ts @@ -16,22 +16,24 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; + import parser from 'vue-eslint-parser'; describe('S6299', () => { - const ruleTesterForVue = new RuleTester({ - parser, - }); - const ruleTester = new RuleTester(); + it('S6299', () => { + const ruleTesterForVue = new RuleTester({ + parser, + }); + const ruleTester = new RuleTester(); - const message = `Make sure bypassing Vue built-in sanitization is safe here.`; - const testName = 'Disabling Vue.js built-in escaping is security-sensitive'; + const message = `Make sure bypassing Vue built-in sanitization is safe here.`; + const testName = 'Disabling Vue.js built-in escaping is security-sensitive'; - ruleTesterForVue.run(testName, rule, { - valid: [ - { - code: ` + ruleTesterForVue.run(testName, rule, { + valid: [ + { + code: ` @@ -39,20 +41,20 @@ describe('S6299', () => { alert('hello'); `, - }, - { - code: ` + }, + { + code: ` `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` @@ -60,18 +62,18 @@ describe('S6299', () => { `, - errors: [ - { - message, - line: 3, - column: 12, - endLine: 3, - endColumn: 30, - }, - ], - }, - { - code: ` + errors: [ + { + message, + line: 3, + column: 12, + endLine: 3, + endColumn: 30, + }, + ], + }, + { + code: ` `, - errors: [ - { message, line: 4, column: 12, endLine: 4, endColumn: 27 }, - { message, line: 6, column: 12, endLine: 6, endColumn: 33 }, - ], - }, - ], - }); + errors: [ + { message, line: 4, column: 12, endLine: 4, endColumn: 27 }, + { message, line: 6, column: 12, endLine: 6, endColumn: 33 }, + ], + }, + ], + }); - ruleTester.run(`${testName} JSX`, rule, { - valid: [{ code: `let x =
foo
` }], - invalid: [ - { - code: ` + ruleTester.run(`${testName} JSX`, rule, { + valid: [{ code: `let x =
foo
` }], + invalid: [ + { + code: ` let x =
`, - errors: [{ message, line: 2, column: 20, endLine: 2, endColumn: 52 }], - }, - ], - }); + errors: [{ message, line: 2, column: 20, endLine: 2, endColumn: 52 }], + }, + ], + }); - ruleTester.run(`${testName} JS`, rule, { - valid: [ - { - code: `let x = { domProps: { }} `, - }, - { code: `let x = { domProps: { prop: 'foo' } } ` }, - { - code: ` + ruleTester.run(`${testName} JS`, rule, { + valid: [ + { + code: `let x = { domProps: { }} `, + }, + { code: `let x = { domProps: { prop: 'foo' } } ` }, + { + code: ` createElement({ attrs: { href: tainted @@ -115,9 +117,9 @@ describe('S6299', () => { }, "click here2") `, - }, - { - code: ` + }, + { + code: ` createElement('foo', { attrs: { bar: 'x' @@ -125,9 +127,9 @@ describe('S6299', () => { }, "click here2") `, - }, - { - code: ` + }, + { + code: ` foo('foo', { attrs: { bar: 'x' @@ -135,11 +137,11 @@ describe('S6299', () => { }, "click here2") `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function f (createElement) { return createElement( 'div', @@ -152,11 +154,11 @@ describe('S6299', () => { ); } `, - errors: [{ message, line: 7, column: 17, endLine: 7, endColumn: 36 }], - }, + errors: [{ message, line: 7, column: 17, endLine: 7, endColumn: 36 }], + }, - { - code: ` + { + code: ` Vue.component('custom-element2', { render: function (createElement) { return createElement('a', { @@ -166,11 +168,11 @@ describe('S6299', () => { }, "click here2")}}) `, - errors: [{ message, line: 6, column: 21, endLine: 6, endColumn: 34 }], - }, + errors: [{ message, line: 6, column: 21, endLine: 6, endColumn: 34 }], + }, - { - code: ` + { + code: ` Vue.component('custom-element2', { render: function (h) { return h('a', { @@ -180,11 +182,11 @@ describe('S6299', () => { }, "click here2")}}) `, - errors: [{ message, line: 6, column: 21, endLine: 6, endColumn: 34 }], - }, + errors: [{ message, line: 6, column: 21, endLine: 6, endColumn: 34 }], + }, - { - code: ` + { + code: ` createElement('foo',{ attrs: { href: tainted @@ -192,8 +194,9 @@ describe('S6299', () => { }, "click here2") `, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S6323/unit.test.ts b/packages/jsts/src/rules/S6323/unit.test.ts index 6ca29f023d..6fbd63747d 100644 --- a/packages/jsts/src/rules/S6323/unit.test.ts +++ b/packages/jsts/src/rules/S6323/unit.test.ts @@ -16,139 +16,141 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6323', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Alternation with empty alternatives', rule, { - valid: [ - { - code: `/a/`, - }, - { - code: `/()/`, - }, - { - code: `/(?:)/`, - }, - { - code: `/a|b/`, - }, - { - code: `/a|b|c/`, - }, - { - // exception when used to make group optional - code: `/(a|)/,/(?:a|)/`, - }, - ], - invalid: [ - { - code: `/|/`, - errors: [ - { - message: 'Remove this empty alternative.', - line: 1, - endLine: 1, - column: 2, - endColumn: 3, - }, - { - message: 'Remove this empty alternative.', - line: 1, - endLine: 1, - column: 2, - endColumn: 3, - }, - ], - }, - { - code: `/a|/`, - errors: [ - { - message: 'Remove this empty alternative.', - line: 1, - endLine: 1, - column: 3, - endColumn: 4, - }, - ], - }, - { - code: `/|a/`, - errors: [ - { - message: 'Remove this empty alternative.', - line: 1, - endLine: 1, - column: 2, - endColumn: 3, - }, - ], - }, - { - code: `/a|b|/`, - errors: 1, - }, - { - code: `/a||b/`, - errors: 1, - }, - { - code: `/||/`, - errors: 3, - }, - { - code: `/(|)/`, - errors: 1, - }, - { - code: `/(?:|)/;`, - errors: 1, - }, - { - code: `/(a|)?/`, - errors: 1, - }, - { - code: `/(a|)*/`, - errors: 1, - }, - { - code: `/(a|){1,3}/`, - errors: 1, - }, - { - code: `new RegExp('|')`, - errors: [ - { - message: 'Remove this empty alternative.', - line: 1, - endLine: 1, - column: 13, - endColumn: 14, - }, - { - message: 'Remove this empty alternative.', - line: 1, - endLine: 1, - column: 13, - endColumn: 14, - }, - ], - }, - { - code: `new RegExp('a\\n(|)')`, - errors: [ - { - message: 'Remove this empty alternative.', - line: 1, - endLine: 1, - column: 18, - endColumn: 19, - }, - ], - }, - ], + it('S6323', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Alternation with empty alternatives', rule, { + valid: [ + { + code: `/a/`, + }, + { + code: `/()/`, + }, + { + code: `/(?:)/`, + }, + { + code: `/a|b/`, + }, + { + code: `/a|b|c/`, + }, + { + // exception when used to make group optional + code: `/(a|)/,/(?:a|)/`, + }, + ], + invalid: [ + { + code: `/|/`, + errors: [ + { + message: 'Remove this empty alternative.', + line: 1, + endLine: 1, + column: 2, + endColumn: 3, + }, + { + message: 'Remove this empty alternative.', + line: 1, + endLine: 1, + column: 2, + endColumn: 3, + }, + ], + }, + { + code: `/a|/`, + errors: [ + { + message: 'Remove this empty alternative.', + line: 1, + endLine: 1, + column: 3, + endColumn: 4, + }, + ], + }, + { + code: `/|a/`, + errors: [ + { + message: 'Remove this empty alternative.', + line: 1, + endLine: 1, + column: 2, + endColumn: 3, + }, + ], + }, + { + code: `/a|b|/`, + errors: 1, + }, + { + code: `/a||b/`, + errors: 1, + }, + { + code: `/||/`, + errors: 3, + }, + { + code: `/(|)/`, + errors: 1, + }, + { + code: `/(?:|)/;`, + errors: 1, + }, + { + code: `/(a|)?/`, + errors: 1, + }, + { + code: `/(a|)*/`, + errors: 1, + }, + { + code: `/(a|){1,3}/`, + errors: 1, + }, + { + code: `new RegExp('|')`, + errors: [ + { + message: 'Remove this empty alternative.', + line: 1, + endLine: 1, + column: 13, + endColumn: 14, + }, + { + message: 'Remove this empty alternative.', + line: 1, + endLine: 1, + column: 13, + endColumn: 14, + }, + ], + }, + { + code: `new RegExp('a\\n(|)')`, + errors: [ + { + message: 'Remove this empty alternative.', + line: 1, + endLine: 1, + column: 18, + endColumn: 19, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S6324/unit.test.ts b/packages/jsts/src/rules/S6324/unit.test.ts index 746a8f1f0e..57b792b00b 100644 --- a/packages/jsts/src/rules/S6324/unit.test.ts +++ b/packages/jsts/src/rules/S6324/unit.test.ts @@ -16,109 +16,111 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6324', () => { - const ruleTester = new RuleTester(); - ruleTester.run('No control characters in regular expressions', rule, { - valid: [ - { - code: `/0/`, - }, - { - code: `/\\0/`, - }, - { - code: `/\\x20/`, - }, - { - code: `/\\u0020/`, - }, - { - code: `/\\u{001F}/`, - }, - { - code: `/\\cA/`, - }, - { - code: String.raw`new RegExp('\t')`, - }, - { - code: String.raw`new RegExp('\n')`, - }, - ], - invalid: [ - { - code: `/\\x00/`, - errors: [ - { - message: 'Remove this control character.', - line: 1, - endLine: 1, - column: 2, - endColumn: 6, - }, - ], - }, - { - code: `/\\u001F/`, - errors: [ - { - message: 'Remove this control character.', - line: 1, - endLine: 1, - column: 2, - endColumn: 8, - }, - ], - }, - { - code: `/\\u{001F}/u`, - errors: [ - { - message: 'Remove this control character.', - line: 1, - endLine: 1, - column: 2, - endColumn: 10, - }, - ], - }, - { - code: "var regex = new RegExp('\\x1f\\x1e')", - errors: [ - { - message: String.raw`Remove this control character.`, - line: 1, - endLine: 1, - column: 25, - endColumn: 29, - }, - { - message: String.raw`Remove this control character.`, - line: 1, - endLine: 1, - column: 29, - endColumn: 33, - }, - ], - }, - { - code: "var regex = new RegExp('\\x1fFOO\\x00')", - errors: 2, - }, - { - code: "var regex = new RegExp('FOO\\x1fFOO\\x1f')", - errors: 2, - }, - { - code: "var regex = RegExp('\\x1f')", - errors: 1, - }, - { - code: String.raw`const flags = ''; new RegExp("\\u001F", flags)`, - errors: 1, - }, - ], + it('S6324', () => { + const ruleTester = new RuleTester(); + ruleTester.run('No control characters in regular expressions', rule, { + valid: [ + { + code: `/0/`, + }, + { + code: `/\\0/`, + }, + { + code: `/\\x20/`, + }, + { + code: `/\\u0020/`, + }, + { + code: `/\\u{001F}/`, + }, + { + code: `/\\cA/`, + }, + { + code: String.raw`new RegExp('\t')`, + }, + { + code: String.raw`new RegExp('\n')`, + }, + ], + invalid: [ + { + code: `/\\x00/`, + errors: [ + { + message: 'Remove this control character.', + line: 1, + endLine: 1, + column: 2, + endColumn: 6, + }, + ], + }, + { + code: `/\\u001F/`, + errors: [ + { + message: 'Remove this control character.', + line: 1, + endLine: 1, + column: 2, + endColumn: 8, + }, + ], + }, + { + code: `/\\u{001F}/u`, + errors: [ + { + message: 'Remove this control character.', + line: 1, + endLine: 1, + column: 2, + endColumn: 10, + }, + ], + }, + { + code: "var regex = new RegExp('\\x1f\\x1e')", + errors: [ + { + message: String.raw`Remove this control character.`, + line: 1, + endLine: 1, + column: 25, + endColumn: 29, + }, + { + message: String.raw`Remove this control character.`, + line: 1, + endLine: 1, + column: 29, + endColumn: 33, + }, + ], + }, + { + code: "var regex = new RegExp('\\x1fFOO\\x00')", + errors: 2, + }, + { + code: "var regex = new RegExp('FOO\\x1fFOO\\x1f')", + errors: 2, + }, + { + code: "var regex = RegExp('\\x1f')", + errors: 1, + }, + { + code: String.raw`const flags = ''; new RegExp("\\u001F", flags)`, + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S6326/unit.test.ts b/packages/jsts/src/rules/S6326/unit.test.ts index 8b4acaed80..a38d187fa4 100644 --- a/packages/jsts/src/rules/S6326/unit.test.ts +++ b/packages/jsts/src/rules/S6326/unit.test.ts @@ -16,76 +16,78 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6326', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Regex with multiple spaces', rule, { - valid: [ - { - code: `/ /`, - }, - { - code: `/ {2}/`, - }, - { - code: `/ a /`, - }, - { - // will be reported by S5869 - code: `/[ ]/`, - }, - { - code: ` + it('S6326', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Regex with multiple spaces', rule, { + valid: [ + { + code: `/ /`, + }, + { + code: `/ {2}/`, + }, + { + code: `/ a /`, + }, + { + // will be reported by S5869 + code: `/[ ]/`, + }, + { + code: ` / ( )/; /a | b/; / .* /; / \\w /; / . /; / \\b /;`, - }, - ], - invalid: [ - { - code: `/a b /`, - errors: [ - { - message: 'If multiple spaces are required here, use number quantifier ({3}).', - line: 1, - endLine: 1, - column: 3, - endColumn: 6, - suggestions: [ - { - desc: 'Use quantifier {3}', - output: `/a {3}b /`, - }, - ], - }, - ], - }, - { - code: `/ a /`, - errors: 2, - }, - { - code: `/ */; / +/; / {2}/; / ?/ `, - errors: 4, - }, - { - code: `/(a b)/ `, - errors: 1, - }, - { - code: ` + }, + ], + invalid: [ + { + code: `/a b /`, + errors: [ + { + message: 'If multiple spaces are required here, use number quantifier ({3}).', + line: 1, + endLine: 1, + column: 3, + endColumn: 6, + suggestions: [ + { + desc: 'Use quantifier {3}', + output: `/a {3}b /`, + }, + ], + }, + ], + }, + { + code: `/ a /`, + errors: 2, + }, + { + code: `/ */; / +/; / {2}/; / ?/ `, + errors: 4, + }, + { + code: `/(a b)/ `, + errors: 1, + }, + { + code: ` / ( )/; /a | b/; / .* /; / \\w /; / . /; / \\b /;`, - errors: 6, - }, - ], + errors: 6, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S6328/unit.test.ts b/packages/jsts/src/rules/S6328/unit.test.ts index cdb0d64cf0..9fa1963f51 100644 --- a/packages/jsts/src/rules/S6328/unit.test.ts +++ b/packages/jsts/src/rules/S6328/unit.test.ts @@ -16,176 +16,178 @@ */ import { rule } from './index.js'; import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6328', () => { - const typeAwareRuleTester = new RuleTester(); - typeAwareRuleTester.run('Existing regular expression groups', rule, { - valid: [ - { - code: `replace()`, - }, - { - code: `'str'.replace()`, - }, - { - code: `'str'[replace]()`, - }, - { - code: `'str'.search()`, - }, - { - code: `[].replace()`, - }, - { - code: `'str'.replaceAll(/(\d+)/, '$1')`, - }, - { - code: `'str'.replace(/(\d+)/, '$1')`, - }, - { - code: `'str'.replace(/(\d+)\s(\d+)/, '$1, $2, $1')`, - }, - { - code: `'str'.replace(/(?\w+)/, '$')`, - }, - { - code: `'str'.replace(/(?\w+)\s(?\w+)/, '$, $, $')`, - }, - { - code: `'str'.replace(/(\d+)\s(?\w+)/, '$1, $')`, - }, - { - code: `'str'.replace(/(?\w+)/, '$')`, - }, - { - code: `'str'.replace(/str/, 'abc')`, - }, - { - code: `'str'.replace(/str/, substr)`, - }, - { - code: `'str'.replace(pattern, 'abc')`, - }, - { - code: `'str'.replace(new RegExp('(\d+)'), '$1')`, - }, - { - code: `'str'.replace(new RegExp('(\d'), '$1')`, - }, - ], - invalid: [ - { - code: `'str'.replaceAll(/(\d+)/, '$0')`, - errors: [ - { - message: 'Referencing non-existing group: $0.', - line: 1, - column: 26, - }, - ], - }, - { - code: `'str'.replace(/(\d+)/, '$0')`, - errors: [ - { - message: 'Referencing non-existing group: $0.', - line: 1, - column: 23, - }, - ], - }, - { - code: `'str'.replace(/(\d+)/, '$2')`, - errors: [ - { - message: 'Referencing non-existing group: $2.', - line: 1, - column: 23, - }, - ], - }, - { - code: `'str'.replace(/(\d+)\s(\d+)/, '$0 $1 $2 $3')`, - errors: [ - { - message: 'Referencing non-existing groups: $0, $3.', - line: 1, - column: 28, - }, - ], - }, - { - code: `'str'.replace(/(?\w+)/, '$')`, - errors: [ - { - message: 'Referencing non-existing group: $.', - line: 1, - column: 31, - }, - ], - }, - { - code: `'str'.replace(/(?\w+)\s(?\w+)/, '$ $ $ $')`, - errors: [ - { - message: 'Referencing non-existing groups: $, $.', - line: 1, - column: 45, - }, - ], - }, - { - code: `'str'.replace(/(?\w+)/, '$0 $ $')`, - errors: [ - { - message: 'Referencing non-existing groups: $0, $.', - line: 1, - column: 31, - }, - ], - }, - { - code: `'str'.replaceAll(new RegExp('(\d+)'), '$0')`, - errors: [ - { - message: 'Referencing non-existing group: $0.', - line: 1, - column: 38, - }, - ], - }, - { - code: ` + it('S6328', () => { + const typeAwareRuleTester = new RuleTester(); + typeAwareRuleTester.run('Existing regular expression groups', rule, { + valid: [ + { + code: `replace()`, + }, + { + code: `'str'.replace()`, + }, + { + code: `'str'[replace]()`, + }, + { + code: `'str'.search()`, + }, + { + code: `[].replace()`, + }, + { + code: `'str'.replaceAll(/(\d+)/, '$1')`, + }, + { + code: `'str'.replace(/(\d+)/, '$1')`, + }, + { + code: `'str'.replace(/(\d+)\s(\d+)/, '$1, $2, $1')`, + }, + { + code: `'str'.replace(/(?\w+)/, '$')`, + }, + { + code: `'str'.replace(/(?\w+)\s(?\w+)/, '$, $, $')`, + }, + { + code: `'str'.replace(/(\d+)\s(?\w+)/, '$1, $')`, + }, + { + code: `'str'.replace(/(?\w+)/, '$')`, + }, + { + code: `'str'.replace(/str/, 'abc')`, + }, + { + code: `'str'.replace(/str/, substr)`, + }, + { + code: `'str'.replace(pattern, 'abc')`, + }, + { + code: `'str'.replace(new RegExp('(\d+)'), '$1')`, + }, + { + code: `'str'.replace(new RegExp('(\d'), '$1')`, + }, + ], + invalid: [ + { + code: `'str'.replaceAll(/(\d+)/, '$0')`, + errors: [ + { + message: 'Referencing non-existing group: $0.', + line: 1, + column: 26, + }, + ], + }, + { + code: `'str'.replace(/(\d+)/, '$0')`, + errors: [ + { + message: 'Referencing non-existing group: $0.', + line: 1, + column: 23, + }, + ], + }, + { + code: `'str'.replace(/(\d+)/, '$2')`, + errors: [ + { + message: 'Referencing non-existing group: $2.', + line: 1, + column: 23, + }, + ], + }, + { + code: `'str'.replace(/(\d+)\s(\d+)/, '$0 $1 $2 $3')`, + errors: [ + { + message: 'Referencing non-existing groups: $0, $3.', + line: 1, + column: 28, + }, + ], + }, + { + code: `'str'.replace(/(?\w+)/, '$')`, + errors: [ + { + message: 'Referencing non-existing group: $.', + line: 1, + column: 31, + }, + ], + }, + { + code: `'str'.replace(/(?\w+)\s(?\w+)/, '$ $ $ $')`, + errors: [ + { + message: 'Referencing non-existing groups: $, $.', + line: 1, + column: 45, + }, + ], + }, + { + code: `'str'.replace(/(?\w+)/, '$0 $ $')`, + errors: [ + { + message: 'Referencing non-existing groups: $0, $.', + line: 1, + column: 31, + }, + ], + }, + { + code: `'str'.replaceAll(new RegExp('(\d+)'), '$0')`, + errors: [ + { + message: 'Referencing non-existing group: $0.', + line: 1, + column: 38, + }, + ], + }, + { + code: ` const pattern = '(\d+)'; 'str'.replaceAll(new RegExp(pattern), '$0')`, - errors: [ - { - message: 'Referencing non-existing group: $0.', - line: 3, - column: 47, - }, - ], - }, - { - code: ` + errors: [ + { + message: 'Referencing non-existing group: $0.', + line: 3, + column: 47, + }, + ], + }, + { + code: ` const pattern = /(\d+)/; 'str'.replaceAll(pattern, '$0')`, - errors: [{ message: 'Referencing non-existing group: $0.' }], - }, - ], - }); + errors: [{ message: 'Referencing non-existing group: $0.' }], + }, + ], + }); - const ruleTester = new DefaultParserRuleTester(); - ruleTester.run('Existing regular expression groups reports nothing without types', rule, { - valid: [ - { - code: `'str'.replace(/(\d+)/, '$1')`, - }, - { - code: `'str'.replace(/(\d+)/, '$0')`, - }, - ], - invalid: [], + const ruleTester = new DefaultParserRuleTester(); + ruleTester.run('Existing regular expression groups reports nothing without types', rule, { + valid: [ + { + code: `'str'.replace(/(\d+)/, '$1')`, + }, + { + code: `'str'.replace(/(\d+)/, '$0')`, + }, + ], + invalid: [], + }); }); }); diff --git a/packages/jsts/src/rules/S6331/unit.test.ts b/packages/jsts/src/rules/S6331/unit.test.ts index 5b5a5fc3d6..355c1b09a9 100644 --- a/packages/jsts/src/rules/S6331/unit.test.ts +++ b/packages/jsts/src/rules/S6331/unit.test.ts @@ -16,102 +16,104 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6331', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Empty groups', rule, { - valid: [ - { - code: `/\\(\\)/`, - }, - { - code: `/(a)/`, - }, - { - code: `/(a|)/`, - }, - { - code: `/(a|b)/`, - }, - { - code: `/(\d+)/`, - }, - ], - invalid: [ - { - code: `/()/`, - errors: [ - { - message: 'Remove this empty group.', - line: 1, - endLine: 1, - column: 2, - endColumn: 4, - }, - ], - }, - { - code: `new RegExp("\\u{000000000061}()")`, - errors: [ - { - message: 'Remove this empty group.', - line: 1, - endLine: 1, - column: 29, - endColumn: 31, - }, - ], - }, - { - code: `/(|)/`, - errors: 1, - }, - { - code: `/(?:)/`, - errors: 1, - }, - { - code: `new RegExp('')`, // parsed as /(?:)/ - errors: 1, - }, - { - // \u0009 is unicode escape for TAB - code: `new RegExp('\\u0009(|)')`, - errors: [ - { - message: 'Remove this empty group.', - line: 1, - endLine: 1, - column: 19, - endColumn: 22, - }, - ], - }, - { - code: `new RegExp('\\t(|)')`, - errors: [ - { - message: 'Remove this empty group.', - line: 1, - endLine: 1, - column: 15, - endColumn: 18, - }, - ], - }, - { - code: `new RegExp('\\n(|)')`, - errors: [ - { - message: 'Remove this empty group.', - line: 1, - endLine: 1, - column: 16, - endColumn: 18, - }, - ], - }, - ], + it('S6331', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Empty groups', rule, { + valid: [ + { + code: `/\\(\\)/`, + }, + { + code: `/(a)/`, + }, + { + code: `/(a|)/`, + }, + { + code: `/(a|b)/`, + }, + { + code: `/(\d+)/`, + }, + ], + invalid: [ + { + code: `/()/`, + errors: [ + { + message: 'Remove this empty group.', + line: 1, + endLine: 1, + column: 2, + endColumn: 4, + }, + ], + }, + { + code: `new RegExp("\\u{000000000061}()")`, + errors: [ + { + message: 'Remove this empty group.', + line: 1, + endLine: 1, + column: 29, + endColumn: 31, + }, + ], + }, + { + code: `/(|)/`, + errors: 1, + }, + { + code: `/(?:)/`, + errors: 1, + }, + { + code: `new RegExp('')`, // parsed as /(?:)/ + errors: 1, + }, + { + // \u0009 is unicode escape for TAB + code: `new RegExp('\\u0009(|)')`, + errors: [ + { + message: 'Remove this empty group.', + line: 1, + endLine: 1, + column: 19, + endColumn: 22, + }, + ], + }, + { + code: `new RegExp('\\t(|)')`, + errors: [ + { + message: 'Remove this empty group.', + line: 1, + endLine: 1, + column: 15, + endColumn: 18, + }, + ], + }, + { + code: `new RegExp('\\n(|)')`, + errors: [ + { + message: 'Remove this empty group.', + line: 1, + endLine: 1, + column: 16, + endColumn: 18, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S6351/unit.test.ts b/packages/jsts/src/rules/S6351/unit.test.ts index 7c07df96c2..91b87f8705 100644 --- a/packages/jsts/src/rules/S6351/unit.test.ts +++ b/packages/jsts/src/rules/S6351/unit.test.ts @@ -16,115 +16,116 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6351', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Regular expressions with the global flag should be used with caution', rule, { - valid: [ - { - code: `/none/;`, - }, - { - code: `/unicode/u;`, - }, - { - code: `/global/g;`, - }, - { - code: `RegExp('none');`, - }, - { - code: `RegExp('global', 'g');`, - }, - { - code: `new RegExp('global', 'g');`, - }, - { - code: `/sticky/y; `, - }, - { - code: `RegExp('sticky', 'y');`, - }, - { - code: `new RegExp('sticky', 'y');`, - }, - { - code: `while (condition) {/foo/g.exec(input);}`, - }, - { - code: `while (() => /foo/g.exec(input)) {}`, - }, - { - code: `const re = /foo/g; while (re.exec(input)) {}`, - }, - { - code: `while (exec(input)) {}`, - }, - { - code: `while (/foo/g.execute(input)) {}`, - }, - { - code: `while (/foo/u.exec(input)) {}`, - }, - { - code: `while (RegExp('foo').exec(input)) {}`, - }, - { - code: ` + it('S6351', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Regular expressions with the global flag should be used with caution', rule, { + valid: [ + { + code: `/none/;`, + }, + { + code: `/unicode/u;`, + }, + { + code: `/global/g;`, + }, + { + code: `RegExp('none');`, + }, + { + code: `RegExp('global', 'g');`, + }, + { + code: `new RegExp('global', 'g');`, + }, + { + code: `/sticky/y; `, + }, + { + code: `RegExp('sticky', 'y');`, + }, + { + code: `new RegExp('sticky', 'y');`, + }, + { + code: `while (condition) {/foo/g.exec(input);}`, + }, + { + code: `while (() => /foo/g.exec(input)) {}`, + }, + { + code: `const re = /foo/g; while (re.exec(input)) {}`, + }, + { + code: `while (exec(input)) {}`, + }, + { + code: `while (/foo/g.execute(input)) {}`, + }, + { + code: `while (/foo/u.exec(input)) {}`, + }, + { + code: `while (RegExp('foo').exec(input)) {}`, + }, + { + code: ` const re = /foo/; re.test('foo'); re.test('bar'); `, - }, - { - code: ` + }, + { + code: ` const re = /foo/; re.exec('foo'); re.exec('bar'); `, - }, - { - code: ` + }, + { + code: ` const re = /foo/g; re.test('foo'); `, - }, - { - code: ` + }, + { + code: ` const re = /foo/g; re.exec('foo'); `, - }, - { - code: ` + }, + { + code: ` const re = /foo/g; re.test(input); re.test(input); `, - }, - { - code: `re.test(input);`, - }, - { - code: ` + }, + { + code: `re.test(input);`, + }, + { + code: ` const re = /foo/g; re.test(input1); re.lastIndex = 0; re.test(input2); `, - }, - { - code: `let re; re.lastIndex = 0;`, - }, - { - code: `re.lastIndex = 0;`, - }, - { - code: `foo = re.lastIndex;`, - }, - { - code: ` + }, + { + code: `let re; re.lastIndex = 0;`, + }, + { + code: `re.lastIndex = 0;`, + }, + { + code: `foo = re.lastIndex;`, + }, + { + code: ` const re = /foo/g; re.test('foo'); re.test(''); // ok, empty string is used to reset the pattern @@ -135,112 +136,113 @@ describe('S6351', () => { re2.test(""); // ok, empty string is used to reset the pattern re2.test('bar'); `, - }, - ], - invalid: [ - { - code: `/globalsticky/gy;`, - errors: [ - { - message: JSON.stringify({ - message: `Remove the 'g' flag from this regex as it is shadowed by the 'y' flag.`, - secondaryLocations: [], - }), - line: 1, - endLine: 1, - column: 1, - endColumn: 17, - }, - ], - options: ['sonar-runtime'], - }, - { - code: `RegExp('globalsticky', 'gy');`, - errors: 1, - }, - { - code: `new RegExp('globalsticky', 'gy');`, - errors: 1, - }, - { - code: `while (/foo/g.exec(input)) {}`, - errors: [ - { - message: JSON.stringify({ - message: `Extract this regular expression to avoid infinite loop.`, - secondaryLocations: [], - }), - line: 1, - endLine: 1, - column: 8, - endColumn: 14, - }, - ], - options: ['sonar-runtime'], - }, - { - code: `do {} while (/foo/g.exec(input));`, - errors: 1, - }, - { - code: `while ((/foo/g.exec(input)) !== null) {}`, - errors: 1, - }, - { - code: `while (RegExp('foo', 'g').exec(input)) {}`, - errors: 1, - }, - { - code: `while (new RegExp('foo', 'g').exec(input)) {}`, - errors: 1, - }, - { - code: ` + }, + ], + invalid: [ + { + code: `/globalsticky/gy;`, + errors: [ + { + message: JSON.stringify({ + message: `Remove the 'g' flag from this regex as it is shadowed by the 'y' flag.`, + secondaryLocations: [], + }), + line: 1, + endLine: 1, + column: 1, + endColumn: 17, + }, + ], + options: ['sonar-runtime'], + }, + { + code: `RegExp('globalsticky', 'gy');`, + errors: 1, + }, + { + code: `new RegExp('globalsticky', 'gy');`, + errors: 1, + }, + { + code: `while (/foo/g.exec(input)) {}`, + errors: [ + { + message: JSON.stringify({ + message: `Extract this regular expression to avoid infinite loop.`, + secondaryLocations: [], + }), + line: 1, + endLine: 1, + column: 8, + endColumn: 14, + }, + ], + options: ['sonar-runtime'], + }, + { + code: `do {} while (/foo/g.exec(input));`, + errors: 1, + }, + { + code: `while ((/foo/g.exec(input)) !== null) {}`, + errors: 1, + }, + { + code: `while (RegExp('foo', 'g').exec(input)) {}`, + errors: 1, + }, + { + code: `while (new RegExp('foo', 'g').exec(input)) {}`, + errors: 1, + }, + { + code: ` const re = /foo/g; re.test('foo'); re.test('bar'); `, - errors: [ - { - message: JSON.stringify({ - message: `Remove the 'g' flag from this regex as it is used on different inputs.`, - secondaryLocations: [ - { message: 'Usage 1', column: 8, line: 3, endColumn: 22, endLine: 3 }, - { message: 'Usage 2', column: 8, line: 4, endColumn: 22, endLine: 4 }, - ], - }), - line: 2, - endLine: 2, - column: 20, - endColumn: 26, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + errors: [ + { + message: JSON.stringify({ + message: `Remove the 'g' flag from this regex as it is used on different inputs.`, + secondaryLocations: [ + { message: 'Usage 1', column: 8, line: 3, endColumn: 22, endLine: 3 }, + { message: 'Usage 2', column: 8, line: 4, endColumn: 22, endLine: 4 }, + ], + }), + line: 2, + endLine: 2, + column: 20, + endColumn: 26, + }, + ], + options: ['sonar-runtime'], + }, + { + code: ` const re = RegExp('foo', 'g'); re.test('foo'); re.test('bar'); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const re = new RegExp('foo', 'g'); re.test('foo'); re.test('bar'); `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const re = /foo/g; re.exec('foo'); re.exec('bar'); `, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S6353/unit.test.ts b/packages/jsts/src/rules/S6353/unit.test.ts index 78cd8cf6c8..689203dee8 100644 --- a/packages/jsts/src/rules/S6353/unit.test.ts +++ b/packages/jsts/src/rules/S6353/unit.test.ts @@ -16,256 +16,258 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6353', () => { - const ruleTester = new RuleTester(); + it('S6353', () => { + const ruleTester = new RuleTester(); - ruleTester.run( - `Regular expression quantifiers and character classes should be used concisely`, - rule, - { - valid: [ - { - code: `/[x]/`, - }, - { - code: `/[12]/`, - }, - { - code: `/[1234]/`, - }, - { - code: `/[1-9abc]/`, - }, - { - code: `/[1-9a-bAB]/`, - }, - { - code: `/[1-9a-bA-Z!]/`, - }, - { - code: `/x?/`, - }, - { - code: `/x*/`, - }, - { - code: `/x+/`, - }, - { - code: `/x{2}/`, - }, - { - code: `/[\\s\\S]/`, - }, - ], - invalid: [ - { - code: `/[\\s\\S]/s`, - errors: [ - { - message: `Use concise character class syntax '.' instead of '[\\s\\S]'.`, - line: 1, - column: 2, - endLine: 1, - endColumn: 8, - }, - ], - }, - { - code: `/[\\d\\D]/`, - errors: [ - { - message: `Use concise character class syntax '.' instead of '[\\d\\D]'.`, - line: 1, - column: 2, - endLine: 1, - endColumn: 8, - }, - ], - }, - { - code: `/[\\w\\W]/`, - errors: [ - { - message: `Use concise character class syntax '.' instead of '[\\w\\W]'.`, - line: 1, - column: 2, - endLine: 1, - endColumn: 8, - }, - ], - }, - { - code: `/[0-9]/`, - errors: [ - { - message: `Use concise character class syntax '\\d' instead of '[0-9]'.`, - line: 1, - column: 2, - endLine: 1, - endColumn: 7, - }, - ], - }, - { - code: `/[^0-9]/`, - errors: [ - { - message: `Use concise character class syntax '\\D' instead of '[^0-9]'.`, - line: 1, - column: 2, - endLine: 1, - endColumn: 8, - }, - ], - }, - { - code: `/[A-Za-z0-9_]/`, - errors: [ - { - message: `Use concise character class syntax '\\w' instead of '[A-Za-z0-9_]'.`, - line: 1, - column: 2, - endLine: 1, - endColumn: 14, - }, - ], - }, - { - code: `/[0-9_A-Za-z]/`, - errors: 1, - }, - { - code: `/[^A-Za-z0-9_]/`, - errors: [ - { - message: `Use concise character class syntax '\\W' instead of '[^A-Za-z0-9_]'.`, - line: 1, - column: 2, - endLine: 1, - endColumn: 15, - }, - ], - }, - { - code: `/[^0-9_A-Za-z]/`, - errors: 1, - }, - { - code: `/x{0,1}/`, - errors: [ - { - message: `Use concise quantifier syntax '?' instead of '{0,1}'.`, - line: 1, - column: 2, - endLine: 1, - endColumn: 8, - }, - ], - }, - { - code: `/x{0,1}?/`, - errors: 1, - }, - { - code: `/x{0,}/`, - errors: [ - { - message: `Use concise quantifier syntax '*' instead of '{0,}'.`, - line: 1, - column: 2, - endLine: 1, - endColumn: 7, - }, - ], - }, - { - code: `/(x\\w+){0}/`, - errors: [ - { - message: `Remove redundant (x\\w+){0}.`, - line: 1, - column: 2, - endLine: 1, - endColumn: 11, - }, - ], - }, - { - code: `/x{0,0}/`, - errors: [ - { - message: `Remove redundant x{0,0}.`, - line: 1, - column: 2, - endLine: 1, - endColumn: 8, - }, - ], - }, - { - code: `/(x\\w+){1}/`, - errors: [ - { - message: `Remove redundant quantifier {1}.`, - line: 1, - column: 2, - endLine: 1, - endColumn: 11, - }, - ], - }, - { - code: `/x{1,1}/`, - errors: [ - { - message: `Remove redundant quantifier {1,1}.`, - line: 1, - column: 2, - endLine: 1, - endColumn: 8, - }, - ], - }, - { - code: `/x{0,}?/`, - errors: 1, - }, - { - code: `/x{1,}/`, - errors: [ - { - message: `Use concise quantifier syntax '+' instead of '{1,}'.`, - line: 1, - column: 2, - endLine: 1, - endColumn: 7, - }, - ], - }, - { - code: `/x{1,}?/`, - errors: 1, - }, - { - code: `/x{2,2}/`, - errors: [ - { - message: `Use concise quantifier syntax '{2}' instead of '{2,2}'.`, - line: 1, - column: 2, - endLine: 1, - endColumn: 8, - }, - ], - }, - { - code: `/x{2,2}?/`, - errors: 1, - }, - ], - }, - ); + ruleTester.run( + `Regular expression quantifiers and character classes should be used concisely`, + rule, + { + valid: [ + { + code: `/[x]/`, + }, + { + code: `/[12]/`, + }, + { + code: `/[1234]/`, + }, + { + code: `/[1-9abc]/`, + }, + { + code: `/[1-9a-bAB]/`, + }, + { + code: `/[1-9a-bA-Z!]/`, + }, + { + code: `/x?/`, + }, + { + code: `/x*/`, + }, + { + code: `/x+/`, + }, + { + code: `/x{2}/`, + }, + { + code: `/[\\s\\S]/`, + }, + ], + invalid: [ + { + code: `/[\\s\\S]/s`, + errors: [ + { + message: `Use concise character class syntax '.' instead of '[\\s\\S]'.`, + line: 1, + column: 2, + endLine: 1, + endColumn: 8, + }, + ], + }, + { + code: `/[\\d\\D]/`, + errors: [ + { + message: `Use concise character class syntax '.' instead of '[\\d\\D]'.`, + line: 1, + column: 2, + endLine: 1, + endColumn: 8, + }, + ], + }, + { + code: `/[\\w\\W]/`, + errors: [ + { + message: `Use concise character class syntax '.' instead of '[\\w\\W]'.`, + line: 1, + column: 2, + endLine: 1, + endColumn: 8, + }, + ], + }, + { + code: `/[0-9]/`, + errors: [ + { + message: `Use concise character class syntax '\\d' instead of '[0-9]'.`, + line: 1, + column: 2, + endLine: 1, + endColumn: 7, + }, + ], + }, + { + code: `/[^0-9]/`, + errors: [ + { + message: `Use concise character class syntax '\\D' instead of '[^0-9]'.`, + line: 1, + column: 2, + endLine: 1, + endColumn: 8, + }, + ], + }, + { + code: `/[A-Za-z0-9_]/`, + errors: [ + { + message: `Use concise character class syntax '\\w' instead of '[A-Za-z0-9_]'.`, + line: 1, + column: 2, + endLine: 1, + endColumn: 14, + }, + ], + }, + { + code: `/[0-9_A-Za-z]/`, + errors: 1, + }, + { + code: `/[^A-Za-z0-9_]/`, + errors: [ + { + message: `Use concise character class syntax '\\W' instead of '[^A-Za-z0-9_]'.`, + line: 1, + column: 2, + endLine: 1, + endColumn: 15, + }, + ], + }, + { + code: `/[^0-9_A-Za-z]/`, + errors: 1, + }, + { + code: `/x{0,1}/`, + errors: [ + { + message: `Use concise quantifier syntax '?' instead of '{0,1}'.`, + line: 1, + column: 2, + endLine: 1, + endColumn: 8, + }, + ], + }, + { + code: `/x{0,1}?/`, + errors: 1, + }, + { + code: `/x{0,}/`, + errors: [ + { + message: `Use concise quantifier syntax '*' instead of '{0,}'.`, + line: 1, + column: 2, + endLine: 1, + endColumn: 7, + }, + ], + }, + { + code: `/(x\\w+){0}/`, + errors: [ + { + message: `Remove redundant (x\\w+){0}.`, + line: 1, + column: 2, + endLine: 1, + endColumn: 11, + }, + ], + }, + { + code: `/x{0,0}/`, + errors: [ + { + message: `Remove redundant x{0,0}.`, + line: 1, + column: 2, + endLine: 1, + endColumn: 8, + }, + ], + }, + { + code: `/(x\\w+){1}/`, + errors: [ + { + message: `Remove redundant quantifier {1}.`, + line: 1, + column: 2, + endLine: 1, + endColumn: 11, + }, + ], + }, + { + code: `/x{1,1}/`, + errors: [ + { + message: `Remove redundant quantifier {1,1}.`, + line: 1, + column: 2, + endLine: 1, + endColumn: 8, + }, + ], + }, + { + code: `/x{0,}?/`, + errors: 1, + }, + { + code: `/x{1,}/`, + errors: [ + { + message: `Use concise quantifier syntax '+' instead of '{1,}'.`, + line: 1, + column: 2, + endLine: 1, + endColumn: 7, + }, + ], + }, + { + code: `/x{1,}?/`, + errors: 1, + }, + { + code: `/x{2,2}/`, + errors: [ + { + message: `Use concise quantifier syntax '{2}' instead of '{2,2}'.`, + line: 1, + column: 2, + endLine: 1, + endColumn: 8, + }, + ], + }, + { + code: `/x{2,2}?/`, + errors: 1, + }, + ], + }, + ); + }); }); diff --git a/packages/jsts/src/rules/S6418/unit.test.ts b/packages/jsts/src/rules/S6418/unit.test.ts index 215bc11da6..a0bc2e9ef1 100644 --- a/packages/jsts/src/rules/S6418/unit.test.ts +++ b/packages/jsts/src/rules/S6418/unit.test.ts @@ -16,27 +16,29 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './rule.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6418', () => { - const ruleTester = new RuleTester(); + it('S6418', () => { + const ruleTester = new RuleTester(); - ruleTester.run('Rule S6418 - no-hardcoded-secrets', rule, { - valid: [], - invalid: [ - // we're verifying that given a broken RegExp, the rule still works. - { - code: ` + ruleTester.run('Rule S6418 - no-hardcoded-secrets', rule, { + valid: [], + invalid: [ + // we're verifying that given a broken RegExp, the rule still works. + { + code: ` secret = '9ah9w8dha9w8hd98h'; `, - options: [ - { - secretWords: 'sel/\\', - randomnessSensibility: 0.5, - }, - ], - errors: 1, - }, - ], + options: [ + { + secretWords: 'sel/\\', + randomnessSensibility: 0.5, + }, + ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S6439/unit.test.ts b/packages/jsts/src/rules/S6439/unit.test.ts index 86107aba3f..56a7d8c0c9 100644 --- a/packages/jsts/src/rules/S6439/unit.test.ts +++ b/packages/jsts/src/rules/S6439/unit.test.ts @@ -16,13 +16,14 @@ */ import { rule } from './index.js'; import { DefaultParserRuleTester, RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6439', () => { - new RuleTester().run('', rule, { - valid: [ - { - code: ` + it('S6439', () => { + new RuleTester().run('', rule, { + valid: [ + { + code: ` const Component = (count, collection) => { count = 1; return ( @@ -32,9 +33,9 @@ describe('S6439', () => { ) } `, - }, - { - code: ` + }, + { + code: ` const Component = (count: boolean, collection) => { return (
@@ -43,9 +44,9 @@ describe('S6439', () => { ) } `, - }, - { - code: ` + }, + { + code: ` const Component = (collection) => { let test = ''; return ( @@ -55,11 +56,11 @@ describe('S6439', () => { ) } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` const Component = (count: number, collection) => { return (
@@ -68,17 +69,17 @@ describe('S6439', () => { ) } `, - errors: [ - { - message: 'Convert the conditional to a boolean to avoid leaked value', - line: 5, - column: 16, - endLine: 5, - endColumn: 21, - suggestions: [ - { - desc: 'Convert the conditional to a boolean', - output: ` + errors: [ + { + message: 'Convert the conditional to a boolean to avoid leaked value', + line: 5, + column: 16, + endLine: 5, + endColumn: 21, + suggestions: [ + { + desc: 'Convert the conditional to a boolean', + output: ` const Component = (count: number, collection) => { return (
@@ -87,13 +88,13 @@ describe('S6439', () => { ) } `, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` const Component = (collection) => { const count = 0; return ( @@ -103,17 +104,17 @@ describe('S6439', () => { ) } `, - errors: [ - { - message: 'Convert the conditional to a boolean to avoid leaked value', - line: 6, - column: 16, - endLine: 6, - endColumn: 21, - suggestions: [ - { - desc: 'Convert the conditional to a boolean', - output: ` + errors: [ + { + message: 'Convert the conditional to a boolean to avoid leaked value', + line: 6, + column: 16, + endLine: 6, + endColumn: 21, + suggestions: [ + { + desc: 'Convert the conditional to a boolean', + output: ` const Component = (collection) => { const count = 0; return ( @@ -123,13 +124,13 @@ describe('S6439', () => { ) } `, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` const Component = (collection: Array) => { return (
@@ -138,17 +139,17 @@ describe('S6439', () => { ) } `, - errors: [ - { - message: 'Convert the conditional to a boolean to avoid leaked value', - line: 5, - column: 16, - endLine: 5, - endColumn: 33, - suggestions: [ - { - desc: 'Convert the conditional to a boolean', - output: ` + errors: [ + { + message: 'Convert the conditional to a boolean to avoid leaked value', + line: 5, + column: 16, + endLine: 5, + endColumn: 33, + suggestions: [ + { + desc: 'Convert the conditional to a boolean', + output: ` const Component = (collection: Array) => { return (
@@ -157,13 +158,13 @@ describe('S6439', () => { ) } `, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` const Component = (test: number, count: number, collection) => { return (
@@ -172,17 +173,17 @@ describe('S6439', () => { ) } `, - errors: [ - { - message: 'Convert the conditional to a boolean to avoid leaked value', - line: 5, - column: 17, - endLine: 5, - endColumn: 21, - suggestions: [ - { - desc: 'Convert the conditional to a boolean', - output: ` + errors: [ + { + message: 'Convert the conditional to a boolean to avoid leaked value', + line: 5, + column: 17, + endLine: 5, + endColumn: 21, + suggestions: [ + { + desc: 'Convert the conditional to a boolean', + output: ` const Component = (test: number, count: number, collection) => { return (
@@ -191,19 +192,19 @@ describe('S6439', () => { ) } `, - }, - ], - }, - { - message: 'Convert the conditional to a boolean to avoid leaked value', - line: 5, - column: 26, - endLine: 5, - endColumn: 31, - suggestions: [ - { - desc: 'Convert the conditional to a boolean', - output: ` + }, + ], + }, + { + message: 'Convert the conditional to a boolean to avoid leaked value', + line: 5, + column: 26, + endLine: 5, + endColumn: 31, + suggestions: [ + { + desc: 'Convert the conditional to a boolean', + output: ` const Component = (test: number, count: number, collection) => { return (
@@ -212,13 +213,13 @@ describe('S6439', () => { ) } `, - }, - ], - }, - ], - }, - { - code: ` + }, + ], + }, + ], + }, + { + code: ` import react from 'react-native'; const Component = (collection) => { let test = ''; @@ -229,10 +230,10 @@ describe('S6439', () => { ) } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` const react = require('react-native'); const Component = (collection) => { let test = ''; @@ -243,15 +244,15 @@ describe('S6439', () => { ) } `, - errors: 1, - }, - ], - }); + errors: 1, + }, + ], + }); - new DefaultParserRuleTester().run('', rule, { - valid: [ - { - code: ` + new DefaultParserRuleTester().run('', rule, { + valid: [ + { + code: ` const Component = (collection) => { const count = 0; return ( @@ -261,8 +262,9 @@ describe('S6439', () => { ) } `, - }, - ], - invalid: [], + }, + ], + invalid: [], + }); }); }); diff --git a/packages/jsts/src/rules/S6479/unit.test.ts b/packages/jsts/src/rules/S6479/unit.test.ts index 9dce3605c6..486acc5d4d 100644 --- a/packages/jsts/src/rules/S6479/unit.test.ts +++ b/packages/jsts/src/rules/S6479/unit.test.ts @@ -16,33 +16,34 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './rule.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6479', () => { - const ruleTester = new RuleTester(); + it('S6479', () => { + const ruleTester = new RuleTester(); - ruleTester.run('Rule S6479 - no-array-index-key', rule, { - valid: [ - { - code: ` + ruleTester.run('Rule S6479 - no-array-index-key', rule, { + valid: [ + { + code: ` export const MyComponent = ({items}) => { return <>{items.map((item, index) => { return
; })}; } `, - }, - { - code: ` + }, + { + code: ` export const MyComponent = ({items}) => { return <>{items.map((item, index) => { return
; })}; } `, - }, - { - code: ` + }, + { + code: ` export const MyComponent = ({items}) => { const renderItems = () => { let i = 0; @@ -55,9 +56,9 @@ export const MyComponent = ({items}) => { return <>{renderItems()}; } `, - }, - { - code: ` + }, + { + code: ` export const MyComponent = ({items}) => { const computeKey = (item, index) => { return item.id + '' + index; @@ -68,9 +69,9 @@ export const MyComponent = ({items}) => { })}; } `, - }, - { - code: ` + }, + { + code: ` export const MyComponent = ({items}) => { const computeKey = (index) => { return index; @@ -81,29 +82,30 @@ export const MyComponent = ({items}) => { })}; } // this test should trigger the rule but it seems ESLint is missing it `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` export const MyComponent = ({items}) => { return <>{items.map((item, index) => { return
{item.id}
; })}; } `, - errors: 1, - }, - { - code: ` + errors: 1, + }, + { + code: ` export const MyComponent = ({items}) => { return <>{items.map((item, index) => { return
{item.id}
; })}; } `, - errors: 1, - }, - ], + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S6557/unit.test.ts b/packages/jsts/src/rules/S6557/unit.test.ts index 155a5d74c5..8b3ad1ce2a 100644 --- a/packages/jsts/src/rules/S6557/unit.test.ts +++ b/packages/jsts/src/rules/S6557/unit.test.ts @@ -16,46 +16,48 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6557', () => { - const ruleTester = new RuleTester(); + it('S6557', () => { + const ruleTester = new RuleTester(); - ruleTester.run(`Decorated rule should provide suggestion with proper message`, rule, { - valid: [ - { - code: `'abc'.starsWith('a');`, - }, - ], - invalid: [ - { - code: `'abc'[0] === 'a';`, - errors: [ - { - messageId: 'preferStartsWith', - suggestions: [ - { - desc: "Use 'String#startsWith' method instead.", - output: `'abc'.startsWith('a');`, - }, - ], - }, - ], - }, - { - code: `'abc'['abc'.length - 1] === 'c';`, - errors: [ - { - messageId: 'preferEndsWith', - suggestions: [ - { - desc: "Use the 'String#endsWith' method instead.", - output: `'abc'.endsWith('c');`, - }, - ], - }, - ], - }, - ], + ruleTester.run(`Decorated rule should provide suggestion with proper message`, rule, { + valid: [ + { + code: `'abc'.starsWith('a');`, + }, + ], + invalid: [ + { + code: `'abc'[0] === 'a';`, + errors: [ + { + messageId: 'preferStartsWith', + suggestions: [ + { + desc: "Use 'String#startsWith' method instead.", + output: `'abc'.startsWith('a');`, + }, + ], + }, + ], + }, + { + code: `'abc'['abc'.length - 1] === 'c';`, + errors: [ + { + messageId: 'preferEndsWith', + suggestions: [ + { + desc: "Use the 'String#endsWith' method instead.", + output: `'abc'.endsWith('c');`, + }, + ], + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S6582/unit.test.ts b/packages/jsts/src/rules/S6582/unit.test.ts index afabfd9e0e..6af8106e01 100644 --- a/packages/jsts/src/rules/S6582/unit.test.ts +++ b/packages/jsts/src/rules/S6582/unit.test.ts @@ -16,16 +16,18 @@ */ import { DefaultParserRuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6582', () => { - const ruleTester = new DefaultParserRuleTester(); - ruleTester.run('Sanitized prefer-optional-chain should not raise a runtime error', rule, { - valid: [ - { - code: `foo && foo.a;`, - }, - ], - invalid: [], + it('S6582', () => { + const ruleTester = new DefaultParserRuleTester(); + ruleTester.run('Sanitized prefer-optional-chain should not raise a runtime error', rule, { + valid: [ + { + code: `foo && foo.a;`, + }, + ], + invalid: [], + }); }); }); diff --git a/packages/jsts/src/rules/S6598/unit.test.ts b/packages/jsts/src/rules/S6598/unit.test.ts index bd2fff8783..1a933e725f 100644 --- a/packages/jsts/src/rules/S6598/unit.test.ts +++ b/packages/jsts/src/rules/S6598/unit.test.ts @@ -16,27 +16,30 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6598', () => { - const ruleTester = new RuleTester(); + it('S6598', () => { + const ruleTester = new RuleTester(); - ruleTester.run(`Decorated rule should reword the issue message`, rule, { - valid: [ - { - code: `type Foo = () => number;`, - }, - ], - invalid: [ - { - code: `interface Foo { (): number; }`, - errors: [ - { - message: 'Interface has only a call signature, you should use a function type instead.', - }, - ], - output: 'type Foo = () => number;', - }, - ], + ruleTester.run(`Decorated rule should reword the issue message`, rule, { + valid: [ + { + code: `type Foo = () => number;`, + }, + ], + invalid: [ + { + code: `interface Foo { (): number; }`, + errors: [ + { + message: + 'Interface has only a call signature, you should use a function type instead.', + }, + ], + output: 'type Foo = () => number;', + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S6606/unit.test.ts b/packages/jsts/src/rules/S6606/unit.test.ts index 0c11139550..c6018ea967 100644 --- a/packages/jsts/src/rules/S6606/unit.test.ts +++ b/packages/jsts/src/rules/S6606/unit.test.ts @@ -16,90 +16,93 @@ */ import { rule } from './rule.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; + import path from 'path'; import parser from '@typescript-eslint/parser'; describe('S6606', () => { - const ruleTester = new RuleTester({ - parser, - parserOptions: { - project: `./tsconfig.json`, - tsconfigRootDir: path.join(import.meta.dirname, 'fixtures'), - }, - }); + it('S6606', () => { + const ruleTester = new RuleTester({ + parser, + parserOptions: { + project: `./tsconfig.json`, + tsconfigRootDir: path.join(import.meta.dirname, 'fixtures'), + }, + }); - ruleTester.run('S6606', rule, { - valid: [ - { - code: ` + ruleTester.run('S6606', rule, { + valid: [ + { + code: ` function foo(value: string) { return value || 'default'; } `, - filename: path.join(import.meta.dirname, 'fixtures/index.ts'), - }, - { - code: ` + filename: path.join(import.meta.dirname, 'fixtures/index.ts'), + }, + { + code: ` function foo(value: string | number) { return value || 'default'; } `, - filename: path.join(import.meta.dirname, 'fixtures/index.ts'), - }, - { - code: ` + filename: path.join(import.meta.dirname, 'fixtures/index.ts'), + }, + { + code: ` function foo(value: boolean | null) { return value || 'default'; } `, - filename: path.join(import.meta.dirname, 'fixtures/index.ts'), - }, - { - code: ` + filename: path.join(import.meta.dirname, 'fixtures/index.ts'), + }, + { + code: ` function foo(value: { baz: number } | null) { return value || 'default'; } `, - filename: path.join(import.meta.dirname, 'fixtures/index.ts'), - }, - { - code: ` + filename: path.join(import.meta.dirname, 'fixtures/index.ts'), + }, + { + code: ` function foo(value: Date | null) { return value || 'default'; } `, - filename: path.join(import.meta.dirname, 'fixtures/index.ts'), - }, - ], - invalid: [ - { - code: ` + filename: path.join(import.meta.dirname, 'fixtures/index.ts'), + }, + ], + invalid: [ + { + code: ` function foo(value: string | null) { return value || 'default'; } `, - filename: path.join(import.meta.dirname, 'fixtures/index.ts'), - errors: 1, - }, - { - code: ` + filename: path.join(import.meta.dirname, 'fixtures/index.ts'), + errors: 1, + }, + { + code: ` function foo(value: number | null) { return value || 'default'; } `, - filename: path.join(import.meta.dirname, 'fixtures/index.ts'), - errors: 1, - }, - { - code: ` + filename: path.join(import.meta.dirname, 'fixtures/index.ts'), + errors: 1, + }, + { + code: ` function foo(value: bigint | null) { return value || 'default'; } `, - filename: path.join(import.meta.dirname, 'fixtures/index.ts'), - errors: 1, - }, - ], + filename: path.join(import.meta.dirname, 'fixtures/index.ts'), + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S6660/unit.test.ts b/packages/jsts/src/rules/S6660/unit.test.ts index 3e1b353c2e..97befb0efe 100644 --- a/packages/jsts/src/rules/S6660/unit.test.ts +++ b/packages/jsts/src/rules/S6660/unit.test.ts @@ -16,24 +16,25 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6660', () => { - const ruleTester = new RuleTester(); + it('S6660', () => { + const ruleTester = new RuleTester(); - ruleTester.run("'If' statement should not be the only statement in 'else' block", rule, { - valid: [ - { - code: ` + ruleTester.run("'If' statement should not be the only statement in 'else' block", rule, { + valid: [ + { + code: ` if (condition) { doSomething(); } `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` if (condition1) { // ... } else { @@ -42,25 +43,25 @@ describe('S6660', () => { } } `, - output: ` + output: ` if (condition1) { // ... } else if (condition2) { // ... } `, - errors: [ - { - message: "'If' statement should not be the only statement in 'else' block", - line: 5, - endLine: 5, - column: 11, - endColumn: 13, - }, - ], - }, - { - code: ` + errors: [ + { + message: "'If' statement should not be the only statement in 'else' block", + line: 5, + endLine: 5, + column: 11, + endColumn: 13, + }, + ], + }, + { + code: ` if (condition3) { // ... } else { @@ -71,7 +72,7 @@ describe('S6660', () => { } } `, - output: ` + output: ` if (condition3) { // ... } else if (condition4) { @@ -80,16 +81,17 @@ describe('S6660', () => { // ... } `, - errors: [ - { - message: "'If' statement should not be the only statement in 'else' block", - line: 5, - endLine: 5, - column: 11, - endColumn: 13, - }, - ], - }, - ], + errors: [ + { + message: "'If' statement should not be the only statement in 'else' block", + line: 5, + endLine: 5, + column: 11, + endColumn: 13, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S6661/unit.test.ts b/packages/jsts/src/rules/S6661/unit.test.ts index eade84ed80..469166ba6a 100644 --- a/packages/jsts/src/rules/S6661/unit.test.ts +++ b/packages/jsts/src/rules/S6661/unit.test.ts @@ -17,78 +17,80 @@ import { NoTypeCheckingRuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; import path from 'path'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6661', () => { - process.chdir(import.meta.dirname); // change current working dir to avoid the package.json lookup to up in the tree - const ruleTester = new NoTypeCheckingRuleTester(); + it('S6661', () => { + process.chdir(import.meta.dirname); // change current working dir to avoid the package.json lookup to up in the tree + const ruleTester = new NoTypeCheckingRuleTester(); - ruleTester.run('Object spread syntax should be used instead of "Object.assign"', rule, { - valid: [ - { - code: `Object.assign(foo, bar);`, - }, - ], - invalid: [ - { - code: `const a = Object.assign({}, foo);`, - output: `const a = { ...foo};`, - errors: [ - { - messageId: 'useSpreadMessage', - line: 1, - endLine: 1, - column: 11, - endColumn: 24, - }, - ], - }, - { - code: `const b = Object.assign({}, foo, bar);`, - output: `const b = { ...foo, ...bar};`, - errors: [ - { - messageId: 'useSpreadMessage', - line: 1, - endLine: 1, - column: 11, - endColumn: 24, - }, - ], - }, - { - code: ` + ruleTester.run('Object spread syntax should be used instead of "Object.assign"', rule, { + valid: [ + { + code: `Object.assign(foo, bar);`, + }, + ], + invalid: [ + { + code: `const a = Object.assign({}, foo);`, + output: `const a = { ...foo};`, + errors: [ + { + messageId: 'useSpreadMessage', + line: 1, + endLine: 1, + column: 11, + endColumn: 24, + }, + ], + }, + { + code: `const b = Object.assign({}, foo, bar);`, + output: `const b = { ...foo, ...bar};`, + errors: [ + { + messageId: 'useSpreadMessage', + line: 1, + endLine: 1, + column: 11, + endColumn: 24, + }, + ], + }, + { + code: ` var assign = Object.assign; const b = assign({}, foo, bar);`, - output: ` + output: ` var assign = Object.assign; const b = { ...foo, ...bar};`, - errors: [ + errors: [ + { + messageId: 'useSpreadMessage', + line: 3, + endLine: 3, + column: 11, + endColumn: 17, + }, + ], + }, + ], + }); + + const filename = path.join(import.meta.dirname, 'fixtures', 'unsupported-node', 'file.js'); + + ruleTester.run( + 'When the project does not support the object spread syntax, the rule should be ignored', + rule, + { + valid: [ { - messageId: 'useSpreadMessage', - line: 3, - endLine: 3, - column: 11, - endColumn: 17, + code: `Object.assign({}, bar);`, + filename, }, ], + invalid: [], }, - ], + ); }); - - const filename = path.join(import.meta.dirname, 'fixtures', 'unsupported-node', 'file.js'); - - ruleTester.run( - 'When the project does not support the object spread syntax, the rule should be ignored', - rule, - { - valid: [ - { - code: `Object.assign({}, bar);`, - filename, - }, - ], - invalid: [], - }, - ); }); diff --git a/packages/jsts/src/rules/S6666/unit.test.ts b/packages/jsts/src/rules/S6666/unit.test.ts index 3b8908b087..41f9aa2fe2 100644 --- a/packages/jsts/src/rules/S6666/unit.test.ts +++ b/packages/jsts/src/rules/S6666/unit.test.ts @@ -16,46 +16,48 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6666', () => { - const ruleTester = new RuleTester(); + it('S6666', () => { + const ruleTester = new RuleTester(); - ruleTester.run(`Spread syntax should be used instead of apply()`, rule, { - valid: [ - { - code: `foo.apply(obj, args);`, - }, - ], - invalid: [ - { - code: `foo.apply(null, args);`, - errors: [ - { - messageId: 'preferSpread', - suggestions: [ - { - desc: 'Replace apply() with spread syntax', - output: `foo(...args);`, - }, - ], - }, - ], - }, - { - code: `obj.foo.apply(obj, args);`, - errors: [ - { - messageId: 'preferSpread', - suggestions: [ - { - desc: 'Replace apply() with spread syntax', - output: `obj.foo(...args);`, - }, - ], - }, - ], - }, - ], + ruleTester.run(`Spread syntax should be used instead of apply()`, rule, { + valid: [ + { + code: `foo.apply(obj, args);`, + }, + ], + invalid: [ + { + code: `foo.apply(null, args);`, + errors: [ + { + messageId: 'preferSpread', + suggestions: [ + { + desc: 'Replace apply() with spread syntax', + output: `foo(...args);`, + }, + ], + }, + ], + }, + { + code: `obj.foo.apply(obj, args);`, + errors: [ + { + messageId: 'preferSpread', + suggestions: [ + { + desc: 'Replace apply() with spread syntax', + output: `obj.foo(...args);`, + }, + ], + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S6676/unit.test.ts b/packages/jsts/src/rules/S6676/unit.test.ts index 6f4733490a..8eeb253988 100644 --- a/packages/jsts/src/rules/S6676/unit.test.ts +++ b/packages/jsts/src/rules/S6676/unit.test.ts @@ -16,130 +16,132 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6676', () => { - const ruleTester = new RuleTester(); + it('S6676', () => { + const ruleTester = new RuleTester(); - ruleTester.run(`Calls to .call() and .apply() methods should not be redundant`, rule, { - valid: [ - { - code: `foo.apply(obj, args);`, - }, - ], - invalid: [ - { - code: `foo.call(null);`, - errors: [ - { - messageId: 'unnecessaryCall', - suggestions: [ - { - desc: 'Remove redundant call()', - output: `foo();`, - }, - ], - }, - ], - }, - { - code: `foo.call(null, a, b, c);`, - errors: [ - { - messageId: 'unnecessaryCall', - suggestions: [ - { - desc: 'Remove redundant call()', - output: `foo(a, b, c);`, - }, - ], - }, - ], - }, - { - code: `obj.foo.call(obj);`, - errors: [ - { - messageId: 'unnecessaryCall', - suggestions: [ - { - desc: 'Remove redundant call()', - output: `obj.foo();`, - }, - ], - }, - ], - }, - { - code: `obj.foo.call(obj, x, y, z);`, - errors: [ - { - messageId: 'unnecessaryCall', - suggestions: [ - { - desc: 'Remove redundant call()', - output: `obj.foo(x, y, z);`, - }, - ], - }, - ], - }, - { - code: `foo.apply(null, []);`, - errors: [ - { - messageId: 'unnecessaryCall', - suggestions: [ - { - desc: 'Remove redundant apply()', - output: `foo();`, - }, - ], - }, - ], - }, - { - code: `foo.apply(null, [1, 2, 3]);`, - errors: [ - { - messageId: 'unnecessaryCall', - suggestions: [ - { - desc: 'Remove redundant apply()', - output: `foo(1, 2, 3);`, - }, - ], - }, - ], - }, - { - code: `obj.foo.apply(obj, []);`, - errors: [ - { - messageId: 'unnecessaryCall', - suggestions: [ - { - desc: 'Remove redundant apply()', - output: `obj.foo();`, - }, - ], - }, - ], - }, - { - code: `obj.foo.apply(obj, [1, 2, 3]);`, - errors: [ - { - messageId: 'unnecessaryCall', - suggestions: [ - { - desc: 'Remove redundant apply()', - output: `obj.foo(1, 2, 3);`, - }, - ], - }, - ], - }, - ], + ruleTester.run(`Calls to .call() and .apply() methods should not be redundant`, rule, { + valid: [ + { + code: `foo.apply(obj, args);`, + }, + ], + invalid: [ + { + code: `foo.call(null);`, + errors: [ + { + messageId: 'unnecessaryCall', + suggestions: [ + { + desc: 'Remove redundant call()', + output: `foo();`, + }, + ], + }, + ], + }, + { + code: `foo.call(null, a, b, c);`, + errors: [ + { + messageId: 'unnecessaryCall', + suggestions: [ + { + desc: 'Remove redundant call()', + output: `foo(a, b, c);`, + }, + ], + }, + ], + }, + { + code: `obj.foo.call(obj);`, + errors: [ + { + messageId: 'unnecessaryCall', + suggestions: [ + { + desc: 'Remove redundant call()', + output: `obj.foo();`, + }, + ], + }, + ], + }, + { + code: `obj.foo.call(obj, x, y, z);`, + errors: [ + { + messageId: 'unnecessaryCall', + suggestions: [ + { + desc: 'Remove redundant call()', + output: `obj.foo(x, y, z);`, + }, + ], + }, + ], + }, + { + code: `foo.apply(null, []);`, + errors: [ + { + messageId: 'unnecessaryCall', + suggestions: [ + { + desc: 'Remove redundant apply()', + output: `foo();`, + }, + ], + }, + ], + }, + { + code: `foo.apply(null, [1, 2, 3]);`, + errors: [ + { + messageId: 'unnecessaryCall', + suggestions: [ + { + desc: 'Remove redundant apply()', + output: `foo(1, 2, 3);`, + }, + ], + }, + ], + }, + { + code: `obj.foo.apply(obj, []);`, + errors: [ + { + messageId: 'unnecessaryCall', + suggestions: [ + { + desc: 'Remove redundant apply()', + output: `obj.foo();`, + }, + ], + }, + ], + }, + { + code: `obj.foo.apply(obj, [1, 2, 3]);`, + errors: [ + { + messageId: 'unnecessaryCall', + suggestions: [ + { + desc: 'Remove redundant apply()', + output: `obj.foo(1, 2, 3);`, + }, + ], + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S6679/unit.test.ts b/packages/jsts/src/rules/S6679/unit.test.ts index b21ef241a4..b0b9cf91eb 100644 --- a/packages/jsts/src/rules/S6679/unit.test.ts +++ b/packages/jsts/src/rules/S6679/unit.test.ts @@ -16,70 +16,72 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6679', () => { - const ruleTester = new RuleTester(); + it('S6679', () => { + const ruleTester = new RuleTester(); - ruleTester.run('Number.isNaN() should be used to check for NaN value', rule, { - valid: [{ code: `x > x` }, { code: `x < x` }, { code: `x >= x` }, { code: `x <= x` }], - invalid: [ - { - code: `x === x`, - errors: [ - { - message: "Use 'Number.isNaN()' to check for 'NaN' value", - suggestions: [ - { - desc: `Replace self-compare with Number.isNaN()`, - output: `!Number.isNaN(x)`, - }, - ], - }, - ], - }, - { - code: `x == x`, - errors: [ - { - message: "Use 'Number.isNaN()' to check for 'NaN' value", - suggestions: [ - { - desc: `Replace self-compare with Number.isNaN()`, - output: `!Number.isNaN(x)`, - }, - ], - }, - ], - }, - { - code: `x !== x`, - errors: [ - { - message: "Use 'Number.isNaN()' to check for 'NaN' value", - suggestions: [ - { - desc: `Replace self-compare with Number.isNaN()`, - output: `Number.isNaN(x)`, - }, - ], - }, - ], - }, - { - code: `x != x`, - errors: [ - { - message: "Use 'Number.isNaN()' to check for 'NaN' value", - suggestions: [ - { - desc: `Replace self-compare with Number.isNaN()`, - output: `Number.isNaN(x)`, - }, - ], - }, - ], - }, - ], + ruleTester.run('Number.isNaN() should be used to check for NaN value', rule, { + valid: [{ code: `x > x` }, { code: `x < x` }, { code: `x >= x` }, { code: `x <= x` }], + invalid: [ + { + code: `x === x`, + errors: [ + { + message: "Use 'Number.isNaN()' to check for 'NaN' value", + suggestions: [ + { + desc: `Replace self-compare with Number.isNaN()`, + output: `!Number.isNaN(x)`, + }, + ], + }, + ], + }, + { + code: `x == x`, + errors: [ + { + message: "Use 'Number.isNaN()' to check for 'NaN' value", + suggestions: [ + { + desc: `Replace self-compare with Number.isNaN()`, + output: `!Number.isNaN(x)`, + }, + ], + }, + ], + }, + { + code: `x !== x`, + errors: [ + { + message: "Use 'Number.isNaN()' to check for 'NaN' value", + suggestions: [ + { + desc: `Replace self-compare with Number.isNaN()`, + output: `Number.isNaN(x)`, + }, + ], + }, + ], + }, + { + code: `x != x`, + errors: [ + { + message: "Use 'Number.isNaN()' to check for 'NaN' value", + suggestions: [ + { + desc: `Replace self-compare with Number.isNaN()`, + output: `Number.isNaN(x)`, + }, + ], + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S6749/unit.test.ts b/packages/jsts/src/rules/S6749/unit.test.ts index 88e97215ca..9d5edfb4e4 100644 --- a/packages/jsts/src/rules/S6749/unit.test.ts +++ b/packages/jsts/src/rules/S6749/unit.test.ts @@ -16,26 +16,28 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6749', () => { - const ruleTester = new RuleTester(); - ruleTester.run('Redundant React fragments should be removed', rule, { - valid: [ - { - code: `function Empty() { return <>; }`, - }, - ], - invalid: [ - { - code: `function Child() { return <>; }`, - output: `function Child() { return ; }`, - errors: [ - { - message: 'A fragment with only one child is redundant.', - }, - ], - }, - ], + it('S6749', () => { + const ruleTester = new RuleTester(); + ruleTester.run('Redundant React fragments should be removed', rule, { + valid: [ + { + code: `function Empty() { return <>; }`, + }, + ], + invalid: [ + { + code: `function Child() { return <>; }`, + output: `function Child() { return ; }`, + errors: [ + { + message: 'A fragment with only one child is redundant.', + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S6754/unit.test.ts b/packages/jsts/src/rules/S6754/unit.test.ts index 69abff29ee..317fcaf356 100644 --- a/packages/jsts/src/rules/S6754/unit.test.ts +++ b/packages/jsts/src/rules/S6754/unit.test.ts @@ -16,35 +16,37 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6754', () => { - const ruleTester = new RuleTester(); - ruleTester.run( - 'The return value of "useState" should be destructured and named symmetrically', - rule, - { - valid: [ - { - code: ` + it('S6754', () => { + const ruleTester = new RuleTester(); + ruleTester.run( + 'The return value of "useState" should be destructured and named symmetrically', + rule, + { + valid: [ + { + code: ` import { useState } from 'react'; function useFoo() { const [foo] = useState(); return [foo]; }`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` import { useState } from 'react'; function useFoo() { const [foo, bar] = useState(); return [foo, bar]; }`, - errors: 1, - }, - ], - }, - ); + errors: 1, + }, + ], + }, + ); + }); }); diff --git a/packages/jsts/src/rules/S6788/unit.test.ts b/packages/jsts/src/rules/S6788/unit.test.ts index 7144fac784..9a53ccfc50 100644 --- a/packages/jsts/src/rules/S6788/unit.test.ts +++ b/packages/jsts/src/rules/S6788/unit.test.ts @@ -16,20 +16,21 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6788', () => { - const ruleTester = new RuleTester(); + it('S6788', () => { + const ruleTester = new RuleTester(); - ruleTester.run(`Decorated rule should reword the issue message`, rule, { - valid: [ - { - code: `type Foo = () => number;`, - }, - ], - invalid: [ - { - code: ` + ruleTester.run(`Decorated rule should reword the issue message`, rule, { + valid: [ + { + code: `type Foo = () => number;`, + }, + ], + invalid: [ + { + code: ` class MyComponent extends Component { componentDidMount() { findDOMNode(this).scrollIntoView(); @@ -39,13 +40,14 @@ class MyComponent extends Component { } } `, - errors: [ - { - message: - "Do not use findDOMNode. It doesn't work with function components and is deprecated in StrictMode.", - }, - ], - }, - ], + errors: [ + { + message: + "Do not use findDOMNode. It doesn't work with function components and is deprecated in StrictMode.", + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S6791/unit.test.ts b/packages/jsts/src/rules/S6791/unit.test.ts index eb8d646797..dcd0a86860 100644 --- a/packages/jsts/src/rules/S6791/unit.test.ts +++ b/packages/jsts/src/rules/S6791/unit.test.ts @@ -16,41 +16,43 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6791', () => { - const ruleTester = new RuleTester(); + it('S6791', () => { + const ruleTester = new RuleTester(); - ruleTester.run( - 'The decorator should refine both message and location, and provide a quickfix', - rule, - { - valid: [ - { - code: ` + ruleTester.run( + 'The decorator should refine both message and location, and provide a quickfix', + rule, + { + valid: [ + { + code: ` import React from 'react'; class Component extends React.Component { componentWillMount() {} }`, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` import React from 'react'; class Component extends React.Component { UNSAFE_componentWillMount() {} }`, - errors: [ - { - message: 'UNSAFE_componentWillMount is unsafe for use in async rendering.', - line: 4, - column: 5, - endColumn: 30, - }, - ], - }, - ], - }, - ); + errors: [ + { + message: 'UNSAFE_componentWillMount is unsafe for use in async rendering.', + line: 4, + column: 5, + endColumn: 30, + }, + ], + }, + ], + }, + ); + }); }); diff --git a/packages/jsts/src/rules/S6957/unit.test.ts b/packages/jsts/src/rules/S6957/unit.test.ts index 482a39a09c..65d99057ec 100644 --- a/packages/jsts/src/rules/S6957/unit.test.ts +++ b/packages/jsts/src/rules/S6957/unit.test.ts @@ -18,7 +18,7 @@ import { rule } from './index.js'; import path from 'path/posix'; import { toUnixPath } from '../helpers/index.js'; import { NoTypeCheckingRuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const dirname = import.meta.dirname; const fixtures = path.join(toUnixPath(dirname), 'fixtures'); @@ -27,12 +27,13 @@ const filenameReact15 = path.join(fixtures, 'react15/file.js'); process.chdir(import.meta.dirname); // change current working dir to avoid the package.json lookup to up in the tree describe('S6957', () => { - const ruleTester = new NoTypeCheckingRuleTester(); + it('S6957', () => { + const ruleTester = new NoTypeCheckingRuleTester(); - ruleTester.run('React15', rule, { - valid: [ - { - code: ` + ruleTester.run('React15', rule, { + valid: [ + { + code: ` import React from 'react'; import ReactDOM from 'react-dom'; @@ -61,12 +62,12 @@ ReactDOM.unmountComponentAtNode(container); ReactDOMServer.renderToNodeStream(element); `, - filename: filenameReact15, - }, - ], - invalid: [ - { - code: ` + filename: filenameReact15, + }, + ], + invalid: [ + { + code: ` import React from 'react'; import ReactDOM from 'react-dom'; @@ -80,27 +81,27 @@ React.renderToString(); React.renderToStaticMarkup(); `, - filename: filenameReact15, - errors: 5, - }, - ], - }); + filename: filenameReact15, + errors: 5, + }, + ], + }); - const filenameReact19 = path.join(fixtures, 'react19/file.js'); + const filenameReact19 = path.join(fixtures, 'react19/file.js'); - ruleTester.run('React19', rule, { - valid: [ - { - code: ` + ruleTester.run('React19', rule, { + valid: [ + { + code: ` import React from 'react'; import ReactDOM from 'react-dom'; `, - filename: filenameReact19, - }, - ], - invalid: [ - { - code: ` + filename: filenameReact19, + }, + ], + invalid: [ + { + code: ` import React from 'react'; import ReactDOM from 'react-dom'; @@ -139,29 +140,29 @@ ReactDOM.unmountComponentAtNode(container); ReactDOMServer.renderToNodeStream(element); `, - filename: filenameReact19, - errors: 15, - }, - ], - }); + filename: filenameReact19, + errors: 15, + }, + ], + }); - shouldRaiseAllIssues(path.join(fixtures, 'noreact1/file.js')); - shouldRaiseAllIssues(path.join(fixtures, 'noreact2/file.js')); + shouldRaiseAllIssues(path.join(fixtures, 'noreact1/file.js')); + shouldRaiseAllIssues(path.join(fixtures, 'noreact2/file.js')); - function shouldRaiseAllIssues(filename) { - ruleTester.run(`No React ${filename}`, rule, { - valid: [ - { - code: ` + function shouldRaiseAllIssues(filename) { + ruleTester.run(`No React ${filename}`, rule, { + valid: [ + { + code: ` import React from 'react'; import ReactDOM from 'react-dom'; `, - filename, - }, - ], - invalid: [ - { - code: ` + filename, + }, + ], + invalid: [ + { + code: ` import React from 'react'; import ReactDOM from 'react-dom'; @@ -200,10 +201,11 @@ ReactDOM.unmountComponentAtNode(container); ReactDOMServer.renderToNodeStream(element); `, - filename, - errors: 15, - }, - ], - }); - } + filename, + errors: 15, + }, + ], + }); + } + }); }); diff --git a/packages/jsts/src/rules/S6958/unit.test.ts b/packages/jsts/src/rules/S6958/unit.test.ts index 8b0c2f1818..3ef5063c95 100644 --- a/packages/jsts/src/rules/S6958/unit.test.ts +++ b/packages/jsts/src/rules/S6958/unit.test.ts @@ -16,243 +16,245 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTester = new RuleTester(); describe('S6958', () => { - ruleTester.run('no-literal-call', rule, { - valid: [ - { code: 'foo();' }, - { code: 'obj.foo();' }, - { code: '(function() {})();' }, - { code: '(() => 0)();' }, - { code: 'foo``;' }, - { code: 'obj.foo``;' }, - { code: '(function() {})``;' }, - { code: '(() => 0)``;' }, - ], - invalid: [ - { - code: 'true();', - errors: [ - { - messageId: 'asFunction', - line: 1, - column: 1, - endColumn: 5, - }, - ], - }, - { - code: 'true``;', - errors: [ - { - messageId: 'asTagFunction', - line: 1, - column: 1, - endColumn: 5, - }, - ], - }, - { - code: 'false();', - errors: [ - { - messageId: 'asFunction', - line: 1, - column: 1, - endColumn: 6, - }, - ], - }, - { - code: 'false``;', - errors: [ - { - messageId: 'asTagFunction', - line: 1, - column: 1, - endColumn: 6, - }, - ], - }, - { - code: 'null();', - errors: [ - { - messageId: 'asFunction', - line: 1, - column: 1, - endColumn: 5, - }, - ], - }, - { - code: 'null``;', - errors: [ - { - messageId: 'asTagFunction', - line: 1, - column: 1, - endColumn: 5, - }, - ], - }, - { - code: '100();', - errors: [ - { - messageId: 'asFunction', - line: 1, - column: 1, - endColumn: 4, - }, - ], - }, - { - code: '100``;', - errors: [ - { - messageId: 'asTagFunction', - line: 1, - column: 1, - endColumn: 4, - }, - ], - }, - { - code: '"hello"();', - errors: [ - { - messageId: 'asFunction', - line: 1, - column: 1, - endColumn: 8, - }, - ], - }, - { - code: '`hello```;', - errors: [ - { - messageId: 'asTagFunction', - line: 1, - column: 1, - endColumn: 8, - }, - ], - }, - { - code: '/abc/();', - errors: [ - { - messageId: 'asFunction', - line: 1, - column: 1, - endColumn: 6, - }, - ], - }, - { - code: '/abc/``;', - errors: [ - { - messageId: 'asTagFunction', - line: 1, - column: 1, - endColumn: 6, - }, - ], - }, - { - code: '[1,2,3]();', - errors: [ - { - messageId: 'asFunction', - line: 1, - column: 1, - endColumn: 8, - }, - ], - }, - { - code: '[1,2,3]``;', - errors: [ - { - messageId: 'asTagFunction', - line: 1, - column: 1, - endColumn: 8, - }, - ], - }, - { - code: '({foo: 0})();', - errors: [ - { - messageId: 'asFunction', - line: 1, - column: 2, - endColumn: 10, - }, - ], - }, - { - code: '({foo: 0})``;', - errors: [ - { - messageId: 'asTagFunction', - line: 1, - column: 2, - endColumn: 10, - }, - ], - }, - { - code: '`hello`();', - errors: [ - { - messageId: 'asFunction', - line: 1, - column: 1, - endColumn: 8, - }, - ], - }, - { - code: '"hello"``;', - errors: [ - { - messageId: 'asTagFunction', - line: 1, - column: 1, - endColumn: 8, - }, - ], - }, - { - code: '(class A {})();', - errors: [ - { - messageId: 'asFunction', - line: 1, - column: 2, - endColumn: 12, - }, - ], - }, - { - code: '(class A {})``;', - errors: [ - { - messageId: 'asTagFunction', - line: 1, - column: 2, - endColumn: 12, - }, - ], - }, - ], + it('S6958', () => { + ruleTester.run('no-literal-call', rule, { + valid: [ + { code: 'foo();' }, + { code: 'obj.foo();' }, + { code: '(function() {})();' }, + { code: '(() => 0)();' }, + { code: 'foo``;' }, + { code: 'obj.foo``;' }, + { code: '(function() {})``;' }, + { code: '(() => 0)``;' }, + ], + invalid: [ + { + code: 'true();', + errors: [ + { + messageId: 'asFunction', + line: 1, + column: 1, + endColumn: 5, + }, + ], + }, + { + code: 'true``;', + errors: [ + { + messageId: 'asTagFunction', + line: 1, + column: 1, + endColumn: 5, + }, + ], + }, + { + code: 'false();', + errors: [ + { + messageId: 'asFunction', + line: 1, + column: 1, + endColumn: 6, + }, + ], + }, + { + code: 'false``;', + errors: [ + { + messageId: 'asTagFunction', + line: 1, + column: 1, + endColumn: 6, + }, + ], + }, + { + code: 'null();', + errors: [ + { + messageId: 'asFunction', + line: 1, + column: 1, + endColumn: 5, + }, + ], + }, + { + code: 'null``;', + errors: [ + { + messageId: 'asTagFunction', + line: 1, + column: 1, + endColumn: 5, + }, + ], + }, + { + code: '100();', + errors: [ + { + messageId: 'asFunction', + line: 1, + column: 1, + endColumn: 4, + }, + ], + }, + { + code: '100``;', + errors: [ + { + messageId: 'asTagFunction', + line: 1, + column: 1, + endColumn: 4, + }, + ], + }, + { + code: '"hello"();', + errors: [ + { + messageId: 'asFunction', + line: 1, + column: 1, + endColumn: 8, + }, + ], + }, + { + code: '`hello```;', + errors: [ + { + messageId: 'asTagFunction', + line: 1, + column: 1, + endColumn: 8, + }, + ], + }, + { + code: '/abc/();', + errors: [ + { + messageId: 'asFunction', + line: 1, + column: 1, + endColumn: 6, + }, + ], + }, + { + code: '/abc/``;', + errors: [ + { + messageId: 'asTagFunction', + line: 1, + column: 1, + endColumn: 6, + }, + ], + }, + { + code: '[1,2,3]();', + errors: [ + { + messageId: 'asFunction', + line: 1, + column: 1, + endColumn: 8, + }, + ], + }, + { + code: '[1,2,3]``;', + errors: [ + { + messageId: 'asTagFunction', + line: 1, + column: 1, + endColumn: 8, + }, + ], + }, + { + code: '({foo: 0})();', + errors: [ + { + messageId: 'asFunction', + line: 1, + column: 2, + endColumn: 10, + }, + ], + }, + { + code: '({foo: 0})``;', + errors: [ + { + messageId: 'asTagFunction', + line: 1, + column: 2, + endColumn: 10, + }, + ], + }, + { + code: '`hello`();', + errors: [ + { + messageId: 'asFunction', + line: 1, + column: 1, + endColumn: 8, + }, + ], + }, + { + code: '"hello"``;', + errors: [ + { + messageId: 'asTagFunction', + line: 1, + column: 1, + endColumn: 8, + }, + ], + }, + { + code: '(class A {})();', + errors: [ + { + messageId: 'asFunction', + line: 1, + column: 2, + endColumn: 12, + }, + ], + }, + { + code: '(class A {})``;', + errors: [ + { + messageId: 'asTagFunction', + line: 1, + column: 2, + endColumn: 12, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S6959/unit.test.ts b/packages/jsts/src/rules/S6959/unit.test.ts index 946ebbfa2e..eb98cb5d29 100644 --- a/packages/jsts/src/rules/S6959/unit.test.ts +++ b/packages/jsts/src/rules/S6959/unit.test.ts @@ -16,31 +16,33 @@ */ import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; describe('S6959', () => { - const ruleTester = new RuleTester(); - ruleTester.run('"Array.reduce()" calls should include an initial value', rule, { - valid: [ - { - code: 'xs.reduce((acc, x) => acc + x);', - }, - { - code: '[1,2,3].reduce((acc, x) => acc + x, 0);', - }, - { - code: 'const xs = [1,2,3]; xs.reduce((acc, x) => acc + x, 0);', - }, - ], - invalid: [ - { - code: '[1,2,3].reduce((acc, x) => acc + x);', - errors: 1, - }, - { - code: 'const xs = [1,2,3]; xs.reduce((acc, x) => acc + x);', - errors: 1, - }, - ], + it('S6959', () => { + const ruleTester = new RuleTester(); + ruleTester.run('"Array.reduce()" calls should include an initial value', rule, { + valid: [ + { + code: 'xs.reduce((acc, x) => acc + x);', + }, + { + code: '[1,2,3].reduce((acc, x) => acc + x, 0);', + }, + { + code: 'const xs = [1,2,3]; xs.reduce((acc, x) => acc + x, 0);', + }, + ], + invalid: [ + { + code: '[1,2,3].reduce((acc, x) => acc + x);', + errors: 1, + }, + { + code: 'const xs = [1,2,3]; xs.reduce((acc, x) => acc + x);', + errors: 1, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S881/unit.test.ts b/packages/jsts/src/rules/S881/unit.test.ts index b15701fef0..e388695aba 100644 --- a/packages/jsts/src/rules/S881/unit.test.ts +++ b/packages/jsts/src/rules/S881/unit.test.ts @@ -16,129 +16,131 @@ */ import { DefaultParserRuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { rule } from './index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTester = new DefaultParserRuleTester(); describe('S881', () => { - ruleTester.run('Nested increment (++) and decrement (--) operators should not be used', rule, { - valid: [ - { - code: `i++;`, - }, - { - code: `++i;`, - }, - { - code: `i--;`, - }, - { - code: `--i;`, - }, - { - code: `foo[i]++;`, - }, - { - code: `foo[-i] = 0;`, - }, - { - code: `for (i = 0; i < 10; i++, j++, k++) {}`, - }, - ], - invalid: [ - { - code: `for (i++, j-- ; i < 10; i++) {}`, - errors: [ - { - message: 'Extract this increment operation into a dedicated statement.', - line: 1, - column: 6, - endLine: 1, - endColumn: 9, - }, - { - message: 'Extract this decrement operation into a dedicated statement.', - line: 1, - column: 11, - endLine: 1, - endColumn: 14, - }, - ], - }, - { - code: `foo[i--]++;`, - errors: [ - { - message: 'Extract this decrement operation into a dedicated statement.', - line: 1, - column: 5, - endLine: 1, - endColumn: 8, - }, - ], - }, - { - code: `foo[++i] = 0;`, - errors: 1, - }, - { - code: `if (i++) {}`, - errors: 1, - }, - { - code: `console.log(i++);`, - errors: 1, - }, - { - code: `i = 5 * --i;`, - errors: 1, - }, - { - code: `i = i++ - 1;`, - errors: 1, - }, - { - code: `i = (j++, k++);`, - errors: 2, - }, - { - code: `for (i++, j++ ; i < 10; i++) {}`, - errors: 2, - }, - { - code: `for (var i = 0; i++ < 10; i++) {}`, - errors: 1, - }, - { - code: `for (let el of [foo[i++]]) {}`, - errors: 1, - }, - { - code: `for (var i = 0; i < 10; i = j++ - 2, i++) {}`, - errors: 1, - }, - { - code: `while (i++) {}`, - errors: 1, - }, - { - code: `do {} while (i++);`, - errors: 1, - }, - { - code: `() => { return i++; }`, - errors: 1, - }, - { - code: `() => { throw i++; }`, - errors: 1, - }, - { - code: `switch (i++) { + it('S881', () => { + ruleTester.run('Nested increment (++) and decrement (--) operators should not be used', rule, { + valid: [ + { + code: `i++;`, + }, + { + code: `++i;`, + }, + { + code: `i--;`, + }, + { + code: `--i;`, + }, + { + code: `foo[i]++;`, + }, + { + code: `foo[-i] = 0;`, + }, + { + code: `for (i = 0; i < 10; i++, j++, k++) {}`, + }, + ], + invalid: [ + { + code: `for (i++, j-- ; i < 10; i++) {}`, + errors: [ + { + message: 'Extract this increment operation into a dedicated statement.', + line: 1, + column: 6, + endLine: 1, + endColumn: 9, + }, + { + message: 'Extract this decrement operation into a dedicated statement.', + line: 1, + column: 11, + endLine: 1, + endColumn: 14, + }, + ], + }, + { + code: `foo[i--]++;`, + errors: [ + { + message: 'Extract this decrement operation into a dedicated statement.', + line: 1, + column: 5, + endLine: 1, + endColumn: 8, + }, + ], + }, + { + code: `foo[++i] = 0;`, + errors: 1, + }, + { + code: `if (i++) {}`, + errors: 1, + }, + { + code: `console.log(i++);`, + errors: 1, + }, + { + code: `i = 5 * --i;`, + errors: 1, + }, + { + code: `i = i++ - 1;`, + errors: 1, + }, + { + code: `i = (j++, k++);`, + errors: 2, + }, + { + code: `for (i++, j++ ; i < 10; i++) {}`, + errors: 2, + }, + { + code: `for (var i = 0; i++ < 10; i++) {}`, + errors: 1, + }, + { + code: `for (let el of [foo[i++]]) {}`, + errors: 1, + }, + { + code: `for (var i = 0; i < 10; i = j++ - 2, i++) {}`, + errors: 1, + }, + { + code: `while (i++) {}`, + errors: 1, + }, + { + code: `do {} while (i++);`, + errors: 1, + }, + { + code: `() => { return i++; }`, + errors: 1, + }, + { + code: `() => { throw i++; }`, + errors: 1, + }, + { + code: `switch (i++) { case j--: break; default: break; }`, - errors: 2, - }, - ], + errors: 2, + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S905/unit.test.ts b/packages/jsts/src/rules/S905/unit.test.ts index d0d1959604..b605b12be4 100644 --- a/packages/jsts/src/rules/S905/unit.test.ts +++ b/packages/jsts/src/rules/S905/unit.test.ts @@ -16,24 +16,25 @@ */ import { rule } from './index.js'; import { RuleTester } from '../../../tests/tools/testers/rule-tester.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTester = new RuleTester(); describe('S905', () => { - ruleTester.run('Disallow unused expressions', rule, { - valid: [ - { - code: ` + it('S905', () => { + ruleTester.run('Disallow unused expressions', rule, { + valid: [ + { + code: ` // valid assignments a = 0; x.y = 0; x[y] = 0; x.y += 0; `, - }, - { - code: ` + }, + { + code: ` // valid function / method / constructor calls (presumably with side effects) doSomething(); doSomething(usingArgs); @@ -41,25 +42,25 @@ describe('S905', () => { obj.doSth(args); new A(); `, - }, - { - code: ` + }, + { + code: ` // valid method calls with null-coalescing operator obj?.doSth(); obj?.x?.y?.doSth(); f?.(arg1, arg2); f.g?.h?.(); `, - }, - { - code: ` + }, + { + code: ` // valid delete / void delete x['k']; void ok; `, - }, - { - code: ` + }, + { + code: ` // valid chai code using 'should'-syntax t.should.be.ok; t.should.exist; @@ -67,9 +68,9 @@ describe('S905', () => { [0].should.not.be.empty; foo.should.have.property("bar").with.empty; `, - }, - { - code: ` + }, + { + code: ` // valid chai code using 'expect'-syntax expect(t).to.be.true; expect(u).to.be.undefined; @@ -78,79 +79,80 @@ describe('S905', () => { expect(NaN).to.not.be.finite; expect(foo).to.have.property('bar').with.empty; `, - }, - { - code: ` + }, + { + code: ` ({ onClick: function(){/* ... */} }); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` // invalid isolated literals (surrounded by chai-tests) thisLine.should.be.ignored; 42; expect(42).to.be.atLeast(40); `, - errors: [ - { - message: `Expected an assignment or function call and instead saw an expression.`, - line: 4, - endLine: 4, - column: 9, - endColumn: 12, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Expected an assignment or function call and instead saw an expression.`, + line: 4, + endLine: 4, + column: 9, + endColumn: 12, + }, + ], + }, + { + code: ` // forgotten method calls (surrounded by chai-tests) thisLine.should.be.ignored(1234); someone.forgot().to[0].callAMethod; expect([]).to.be.empty; `, - errors: [ - { - message: `Expected an assignment or function call and instead saw an expression.`, - line: 4, - endLine: 4, - column: 9, - endColumn: 44, - }, - ], - }, - { - code: `({})`, - errors: [ - { - message: `Expected an assignment or function call and instead saw an expression.`, - line: 1, - endLine: 1, - column: 1, - endColumn: 5, - }, - ], - }, - { - code: ` + errors: [ + { + message: `Expected an assignment or function call and instead saw an expression.`, + line: 4, + endLine: 4, + column: 9, + endColumn: 44, + }, + ], + }, + { + code: `({})`, + errors: [ + { + message: `Expected an assignment or function call and instead saw an expression.`, + line: 1, + endLine: 1, + column: 1, + endColumn: 5, + }, + ], + }, + { + code: ` while (true) { ({ onClick: function(){/* ... */} }); }`, - errors: [ - { - message: `Expected an assignment or function call and instead saw an expression.`, - line: 3, - endLine: 5, - column: 11, - endColumn: 14, - }, - ], - }, - ], + errors: [ + { + message: `Expected an assignment or function call and instead saw an expression.`, + line: 3, + endLine: 5, + column: 11, + endColumn: 14, + }, + ], + }, + ], + }); }); }); diff --git a/packages/jsts/src/rules/S930/unit.test.ts b/packages/jsts/src/rules/S930/unit.test.ts index 7b2c265ce1..df4c6156d9 100644 --- a/packages/jsts/src/rules/S930/unit.test.ts +++ b/packages/jsts/src/rules/S930/unit.test.ts @@ -17,103 +17,104 @@ import { rule } from './rule.js'; import { DefaultParserRuleTester } from '../../../tests/tools/testers/rule-tester.js'; import { IssueLocation } from '../helpers/index.js'; -import { describe } from 'node:test'; +import { describe, it } from 'node:test'; const ruleTester = new DefaultParserRuleTester({ sourceType: 'script' }); describe('S930', () => { - ruleTester.run('no-extra-arguments', rule, { - valid: [ - { - code: ` + it('S930', () => { + ruleTester.run('no-extra-arguments', rule, { + valid: [ + { + code: ` function foo(p1, p2) {} foo(1, 2); foo(1); `, - }, - { - code: ` + }, + { + code: ` function foo() { console.log(arguments); } foo(1, 2); `, - }, - { - code: ` + }, + { + code: ` function foo(p1, ...p2) {} foo(1, 2, 3, 4); `, - }, - { - code: ` + }, + { + code: ` let foo = function(...p1) {} foo(1, 2, 3, 4); `, - }, - { - code: ` + }, + { + code: ` let noop = () => {}; function foo(callback = noop) { callback(42); } `, - }, - { - code: ` + }, + { + code: ` let x = () => {}; if (cond) { x = (p1, p2) => 1; } x(1, 2); `, - }, - ], - invalid: [ - { - code: ` + }, + ], + invalid: [ + { + code: ` function foo(p1, p2) {} foo(1, 2, 3); foo(1, 2, 3, 4); `, - errors: [ - message(2, 3, { line: 3, column: 9, endColumn: 12 }), - message(2, 4, { line: 4, column: 9, endColumn: 12 }), - ], - }, - { - code: ` + errors: [ + message(2, 3, { line: 3, column: 9, endColumn: 12 }), + message(2, 4, { line: 4, column: 9, endColumn: 12 }), + ], + }, + { + code: ` function foo(p1, p2) {} // ^^^^^^> foo(1, 2, 3); //^^^ <^ `, - errors: [ - { - messageId: 'sonarRuntime', - data: { - expectedArguments: '2 arguments', - providedArguments: '3 were', - sonarRuntimeData: encodedMessage(2, 3, [ - { message: 'Formal parameters', column: 21, line: 2, endColumn: 27, endLine: 2 }, - { message: 'Extra argument', column: 18, line: 4, endColumn: 19, endLine: 4 }, - ]), + errors: [ + { + messageId: 'sonarRuntime', + data: { + expectedArguments: '2 arguments', + providedArguments: '3 were', + sonarRuntimeData: encodedMessage(2, 3, [ + { message: 'Formal parameters', column: 21, line: 2, endColumn: 27, endLine: 2 }, + { message: 'Extra argument', column: 18, line: 4, endColumn: 19, endLine: 4 }, + ]), + }, }, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + ], + options: ['sonar-runtime'], + }, + { + code: ` var foo = function() { console.log('hello'); } foo(1); `, - errors: [message(0, 1, { line: 5, column: 9, endColumn: 12 })], - }, - { - code: ` + errors: [message(0, 1, { line: 5, column: 9, endColumn: 12 })], + }, + { + code: ` foo(1); // ^ var foo = function() { @@ -121,104 +122,105 @@ describe('S930', () => { console.log('hello'); } `, - errors: [ - { - messageId: 'sonarRuntime', - data: { - expectedArguments: 'no arguments', - providedArguments: '1 was', - sonarRuntimeData: encodedMessage(0, 1, [ - { message: 'Formal parameters', column: 18, line: 4, endColumn: 26, endLine: 4 }, - { message: 'Extra argument', column: 12, line: 2, endColumn: 13, endLine: 2 }, - ]), + errors: [ + { + messageId: 'sonarRuntime', + data: { + expectedArguments: 'no arguments', + providedArguments: '1 was', + sonarRuntimeData: encodedMessage(0, 1, [ + { message: 'Formal parameters', column: 18, line: 4, endColumn: 26, endLine: 4 }, + { message: 'Extra argument', column: 12, line: 2, endColumn: 13, endLine: 2 }, + ]), + }, }, - }, - ], - options: ['sonar-runtime'], - }, - { - code: ` + ], + options: ['sonar-runtime'], + }, + { + code: ` (function(p1, p2){ doSomething1; doSomething2; })(1, 2, 3); `, - errors: [message(2, 3, { line: 2, column: 10, endLine: 5, endColumn: 10 })], - }, - { - code: ` + errors: [message(2, 3, { line: 2, column: 10, endLine: 5, endColumn: 10 })], + }, + { + code: ` let x = function(a, b) { return a + b; }(1, 2, 3); `, - errors: [message(2, 3, { line: 2, column: 17, endLine: 4, endColumn: 10 })], - }, - { - code: ` + errors: [message(2, 3, { line: 2, column: 17, endLine: 4, endColumn: 10 })], + }, + { + code: ` ((a, b) => { return a + b; })(1, 2, 3); `, - errors: [message(2, 3, { line: 2, column: 10, endLine: 4, endColumn: 10 })], - }, - { - code: ` + errors: [message(2, 3, { line: 2, column: 10, endLine: 4, endColumn: 10 })], + }, + { + code: ` let arrow_function = (a, b) => {}; arrow_function(1, 2, 3); `, - errors: [message(2, 3, { line: 3, column: 9, endColumn: 23 })], - }, - { - code: ` + errors: [message(2, 3, { line: 3, column: 9, endColumn: 23 })], + }, + { + code: ` function foo(arguments) { console.log(arguments); } foo(1, 2); `, - errors: [message(1, 2, { line: 5, column: 9, endColumn: 12 })], - }, - { - code: ` + errors: [message(1, 2, { line: 5, column: 9, endColumn: 12 })], + }, + { + code: ` function foo() { let arguments = [3, 4]; console.log(arguments); } foo(1, 2); `, - errors: [message(0, 2, { line: 6, column: 9, endColumn: 12 })], - }, - ], + errors: [message(0, 2, { line: 6, column: 9, endColumn: 12 })], + }, + ], + }); }); -}); -function message(expected: number, provided: number, extra = {}) { - // prettier-ignore - const expectedArguments = + function message(expected: number, provided: number, extra = {}) { + // prettier-ignore + const expectedArguments = expected === 0 ? "no arguments" : expected === 1 ? "1 argument" : `${expected} arguments`; - // prettier-ignore - const providedArguments = + // prettier-ignore + const providedArguments = provided === 0 ? "none was" : provided === 1 ? "1 was" : `${provided} were`; - return { - messageId: 'tooManyArguments', - data: { - expectedArguments, - providedArguments, - }, - ...extra, - }; -} + return { + messageId: 'tooManyArguments', + data: { + expectedArguments, + providedArguments, + }, + ...extra, + }; + } -function encodedMessage(expected: number, provided: number, secondaryLocations: IssueLocation[]) { - const testCaseError = message(expected, provided); + function encodedMessage(expected: number, provided: number, secondaryLocations: IssueLocation[]) { + const testCaseError = message(expected, provided); - return JSON.stringify({ - message: `This function expects ${testCaseError.data?.expectedArguments}, but ${testCaseError.data?.providedArguments} provided.`, - secondaryLocations, - }); -} + return JSON.stringify({ + message: `This function expects ${testCaseError.data?.expectedArguments}, but ${testCaseError.data?.providedArguments} provided.`, + secondaryLocations, + }); + } +});