1919 */
2020import { TSESLint } from '@typescript-eslint/experimental-utils' ;
2121import { ruleTester } from '../rule-tester' ;
22+ import { IssueLocation } from '../../src/utils/locations' ;
2223import rule = require( '../../src/rules/cognitive-complexity' ) ;
2324
2425ruleTester . run ( 'cognitive-complexity' , rule , {
25- valid : [ { code : `function zero_complexity() {}` , options : [ 0 ] } ] ,
26+ valid : [
27+ { code : `function zero_complexity() {}` , options : [ 0 ] } ,
28+ {
29+ code : `
30+ function Component(obj) {
31+ return (
32+ <span>{ obj.title?.text }</span>
33+ );
34+ }` ,
35+ parserOptions : { ecmaFeatures : { jsx : true } } ,
36+ options : [ 0 ] ,
37+ } ,
38+ {
39+ code : `
40+ function Component(obj) {
41+ return (
42+ <>
43+ { obj.isFriendly && <strong>Welcome</strong> }
44+ </>
45+ );
46+ }` ,
47+ parserOptions : { ecmaFeatures : { jsx : true } } ,
48+ options : [ 0 ] ,
49+ } ,
50+ {
51+ code : `
52+ function Component(obj) {
53+ return (
54+ <>
55+ { obj.isFriendly && obj.isLoggedIn && <strong>Welcome</strong> }
56+ </>
57+ );
58+ }` ,
59+ parserOptions : { ecmaFeatures : { jsx : true } } ,
60+ options : [ 0 ] ,
61+ } ,
62+ {
63+ code : `
64+ function Component(obj) {
65+ return (
66+ <>
67+ { obj.x && obj.y && obj.z && <strong>Welcome</strong> }
68+ </>
69+ );
70+ }` ,
71+ parserOptions : { ecmaFeatures : { jsx : true } } ,
72+ options : [ 0 ] ,
73+ } ,
74+ {
75+ code : `
76+ function Component(obj) {
77+ return (
78+ <span title={ obj.title || obj.disclaimer }>Text</span>
79+ );
80+ }` ,
81+ parserOptions : { ecmaFeatures : { jsx : true } } ,
82+ options : [ 0 ] ,
83+ } ,
84+ {
85+ code : `
86+ function Component(obj) {
87+ return (
88+ <button type="button" disabled={ obj.user?.isBot ?? obj.isDemo }>Logout</button>
89+ );
90+ }` ,
91+ parserOptions : { ecmaFeatures : { jsx : true } } ,
92+ options : [ 0 ] ,
93+ } ,
94+ ] ,
2695 invalid : [
2796 // if
2897 {
@@ -196,8 +265,8 @@ ruleTester.run('cognitive-complexity', rule, {
196265 options : [ 0 ] ,
197266 errors : [ message ( 2 ) ] ,
198267 } ,
199- {
200- code : `
268+ testCaseWithSonarRuntime (
269+ `
201270 function check_secondaries() {
202271 if (condition) { // +1 "if"
203272 if (condition) {} else {} // +2 "if", +1 "else"
@@ -217,51 +286,46 @@ ruleTester.run('cognitive-complexity', rule, {
217286
218287 return foo(a && b) && c; // +1 "&&", +1 "&&"
219288 }` ,
220- options : [ 0 , 'sonar-runtime' ] ,
221- errors : [
289+ [
290+ { line : 3 , column : 8 , endLine : 3 , endColumn : 10 , message : '+1' } , // if
291+ { line : 7 , column : 10 , endLine : 7 , endColumn : 14 , message : '+1' } , // else
222292 {
223- messageId : 'sonarRuntime' ,
224- data : {
225- complexityAmount : 13 ,
226- threshold : 0 ,
227- sonarRuntimeData : JSON . stringify ( {
228- secondaryLocations : [
229- { line : 3 , column : 8 , endLine : 3 , endColumn : 10 , message : '+1' } , // if
230- { line : 7 , column : 10 , endLine : 7 , endColumn : 14 , message : '+1' } , // else
231- {
232- line : 4 ,
233- column : 10 ,
234- endLine : 4 ,
235- endColumn : 12 ,
236- message : '+2 (incl. 1 for nesting)' ,
237- } , // if
238- { line : 4 , column : 28 , endLine : 4 , endColumn : 32 , message : '+1' } , // else
239- {
240- line : 6 ,
241- column : 10 ,
242- endLine : 6 ,
243- endColumn : 15 ,
244- message : '+2 (incl. 1 for nesting)' ,
245- } , // catch
246- { line : 11 , column : 8 , endLine : 11 , endColumn : 13 , message : '+1' } , // while
247- { line : 12 , column : 10 , endLine : 12 , endColumn : 15 , message : '+1' } , // break
248- { line : 15 , column : 10 , endLine : 15 , endColumn : 11 , message : '+1' } , // ?
249- { line : 17 , column : 8 , endLine : 17 , endColumn : 14 , message : '+1' } , // switch
250- { line : 19 , column : 27 , endLine : 19 , endColumn : 29 , message : '+1' } , // &&
251- { line : 19 , column : 21 , endLine : 19 , endColumn : 23 , message : '+1' } , // &&
252- ] ,
253- message :
254- 'Refactor this function to reduce its Cognitive Complexity from 13 to the 0 allowed.' ,
255- cost : 13 ,
256- } ) ,
257- ...message ( 13 ) ,
258- cost : 13 ,
259- } ,
260- } ,
293+ line : 4 ,
294+ column : 10 ,
295+ endLine : 4 ,
296+ endColumn : 12 ,
297+ message : '+2 (incl. 1 for nesting)' ,
298+ } , // if
299+ { line : 4 , column : 28 , endLine : 4 , endColumn : 32 , message : '+1' } , // else
300+ {
301+ line : 6 ,
302+ column : 10 ,
303+ endLine : 6 ,
304+ endColumn : 15 ,
305+ message : '+2 (incl. 1 for nesting)' ,
306+ } , // catch
307+ { line : 11 , column : 8 , endLine : 11 , endColumn : 13 , message : '+1' } , // while
308+ { line : 12 , column : 10 , endLine : 12 , endColumn : 15 , message : '+1' } , // break
309+ { line : 15 , column : 10 , endLine : 15 , endColumn : 11 , message : '+1' } , // ?
310+ { line : 17 , column : 8 , endLine : 17 , endColumn : 14 , message : '+1' } , // switch
311+ { line : 19 , column : 27 , endLine : 19 , endColumn : 29 , message : '+1' } , // &&
312+ { line : 19 , column : 21 , endLine : 19 , endColumn : 23 , message : '+1' } , // &&
261313 ] ,
262- } ,
314+ 13 ,
315+ ) ,
263316
264317 // expressions
318+ testCaseWithSonarRuntime (
319+ `
320+ function and_or_locations() {
321+ foo(1 && 2 || 3 && 4);
322+ }` ,
323+ [
324+ { line : 3 , column : 14 , endLine : 3 , endColumn : 16 , message : '+1' } , // &&
325+ { line : 3 , column : 19 , endLine : 3 , endColumn : 21 , message : '+1' } , // ||
326+ { line : 3 , column : 24 , endLine : 3 , endColumn : 26 , message : '+1' } , // &&
327+ ] ,
328+ ) ,
265329 {
266330 code : `
267331 function and_or() {
@@ -516,6 +580,48 @@ ruleTester.run('cognitive-complexity', rule, {
516580 options : [ 0 ] ,
517581 errors : [ message ( 1 , { line : 2 } ) , message ( 1 , { line : 3 } ) ] ,
518582 } ,
583+ testCaseWithSonarRuntime (
584+ `
585+ function Component(obj) {
586+ return (
587+ <>
588+ <span title={ obj.user?.name ?? (obj.isDemo ? 'demo' : 'none') }>Text</span>
589+ </>
590+ );
591+ }` ,
592+ [
593+ { line : 5 , column : 41 , endLine : 5 , endColumn : 43 , message : '+1' } , // ??
594+ { line : 5 , column : 56 , endLine : 5 , endColumn : 57 , message : '+1' } , // ?:
595+ ] ,
596+ ) ,
597+ testCaseWithSonarRuntime (
598+ `
599+ function Component(obj) {
600+ return (
601+ <>
602+ { obj.isUser && (obj.name || obj.surname) }
603+ </>
604+ );
605+ }` ,
606+ [
607+ { line : 5 , column : 25 , endLine : 5 , endColumn : 27 , message : '+1' } , // &&
608+ { line : 5 , column : 38 , endLine : 5 , endColumn : 40 , message : '+1' } , // ||
609+ ] ,
610+ ) ,
611+ testCaseWithSonarRuntime (
612+ `
613+ function Component(obj) {
614+ return (
615+ <>
616+ { obj.isUser && (obj.isDemo ? <strong>Demo</strong> : <em>None</em>) }
617+ </>
618+ );
619+ }` ,
620+ [
621+ { line : 5 , column : 25 , endLine : 5 , endColumn : 27 , message : '+1' } , // &&
622+ { line : 5 , column : 40 , endLine : 5 , endColumn : 41 , message : '+1' } , // ||
623+ ] ,
624+ ) ,
519625 ] ,
520626} ) ;
521627
@@ -655,6 +761,30 @@ class TopLevel {
655761 ] ,
656762} ) ;
657763
764+ function testCaseWithSonarRuntime (
765+ code : string ,
766+ secondaryLocations : IssueLocation [ ] ,
767+ complexity ?: number ,
768+ ) : TSESLint . InvalidTestCase < string , ( number | 'sonar-runtime' ) [ ] > {
769+ const cost = complexity ?? secondaryLocations . length ;
770+ const message = `Refactor this function to reduce its Cognitive Complexity from ${ cost } to the 0 allowed.` ;
771+ const sonarRuntimeData = JSON . stringify ( { secondaryLocations, message, cost } ) ;
772+ return {
773+ code,
774+ parserOptions : { ecmaFeatures : { jsx : true } } ,
775+ options : [ 0 , 'sonar-runtime' ] ,
776+ errors : [
777+ {
778+ messageId : 'sonarRuntime' ,
779+ data : {
780+ threshold : 0 ,
781+ sonarRuntimeData,
782+ } ,
783+ } ,
784+ ] ,
785+ } ;
786+ }
787+
658788function message ( complexityAmount : number , other : Partial < TSESLint . TestCaseError < string > > = { } ) {
659789 return {
660790 messageId : 'refactorFunction' ,
0 commit comments