@@ -149,12 +149,21 @@ describe('Tests for selecting rules', () => {
149149 expect ( ruleNamesFor ( selection7 , 'stubEngine2' ) ) . toEqual ( [ ] )
150150 } ) ;
151151
152- it ( 'When multiple selectors are provided, then they act as a union' , async ( ) => {
153- const selection : RuleSelection = await codeAnalyzer . selectRules ( [
154- 'Security' , // a tag
155- 'stubEngine2' , // an engine name
156- 'stub1RuleD' // a rule name
157- ] ) ;
152+ it . each ( [
153+ {
154+ case : 'multiple selectors are provided' ,
155+ selectors : [
156+ 'Security' , // a tag
157+ 'stubEngine2' , // an engine name
158+ 'stub1RuleD' // a rule name
159+ ]
160+ } ,
161+ {
162+ case : 'using a comma to join two rule selectors' ,
163+ selectors : [ 'Security,stubEngine2,stub1RuleD' ]
164+ }
165+ ] ) ( 'When $case, then it acts like a union' , async ( { selectors} ) => {
166+ const selection : RuleSelection = await codeAnalyzer . selectRules ( selectors ) ;
158167
159168 expect ( selection . getEngineNames ( ) ) . toEqual ( [ 'stubEngine1' , 'stubEngine2' ] ) ;
160169 expect ( ruleNamesFor ( selection , 'stubEngine1' ) ) . toEqual ( [ 'stub1RuleB' , 'stub1RuleD' ] ) ;
@@ -164,14 +173,76 @@ describe('Tests for selecting rules', () => {
164173 expect ( await codeAnalyzer . selectRules ( [ 'all' , 'Performance' , 'DoesNotExist' ] ) ) . toEqual ( await codeAnalyzer . selectRules ( [ 'all' ] ) ) ;
165174 } ) ;
166175
167- it ( 'When colons are used and multiple selectors are provided then we get correct union and intersection behavior' , async ( ) => {
168- const selection : RuleSelection = await codeAnalyzer . selectRules ( [ 'Recommended:Performance' , 'stubEngine2:2' , 'stubEngine2:DoesNotExist' ] ) ;
176+ it . each ( [
177+ {
178+ selector : 'Recommended:Performance,2' , // Equivalent to "(Recommended:Performance),2", or "(Recommended,2):(Performance,2)"
179+ engines : [ 'stubEngine1' , 'stubEngine2' ] ,
180+ stubEngine1Rules : [ 'stub1RuleB' , 'stub1RuleC' ] ,
181+ stubEngine2Rules : [ 'stub2RuleC' ]
182+ } ,
183+ {
184+ selector : 'Recommended,3:Performance' , // Equivalent to "(Recommended,4):Performance", or "(Recommended:Performance),(4:Performance)"
185+ engines : [ 'stubEngine1' ] ,
186+ stubEngine1Rules : [ 'stub1RuleC' , 'stub1RuleE' ] ,
187+ stubEngine2Rules : [ ]
188+ }
189+ ] ) ( 'In the absence of parentheses, colons and commas are resolved from left to right. Case: $selector' , async ( { selector, engines, stubEngine1Rules, stubEngine2Rules} ) => {
190+ const selection : RuleSelection = await codeAnalyzer . selectRules ( [ selector ] ) ;
191+
192+ expect ( selection . getEngineNames ( ) ) . toEqual ( engines ) ;
193+ expect ( ruleNamesFor ( selection , 'stubEngine1' ) ) . toEqual ( stubEngine1Rules ) ;
194+ expect ( ruleNamesFor ( selection , 'stubEngine2' ) ) . toEqual ( stubEngine2Rules ) ;
195+ } ) ;
196+
197+ it . each ( [
198+ {
199+ case : 'colons are used and multiple selectors are provided' ,
200+ selectors : [ 'Recommended:Performance' , 'stubEngine2:2' , 'stubEngine2:DoesNotExist' ]
201+ } ,
202+ {
203+ case : 'colons and commas are nested via parentheses' ,
204+ selectors : [ '(Recommended:Performance),(stubEngine2:2),(stubEngine2:DoesNotExist)' ]
205+ }
206+ ] ) ( 'When $case, then we get correct union and intersection behavior' , async ( { selectors} ) => {
207+ const selection : RuleSelection = await codeAnalyzer . selectRules ( selectors ) ;
169208
170209 expect ( selection . getEngineNames ( ) ) . toEqual ( [ 'stubEngine1' , 'stubEngine2' ] ) ;
171210 expect ( ruleNamesFor ( selection , 'stubEngine1' ) ) . toEqual ( [ 'stub1RuleC' ] ) ;
172211 expect ( ruleNamesFor ( selection , 'stubEngine2' ) ) . toEqual ( [ 'stub2RuleC' ] ) ;
173212 } ) ;
174213
214+ it ( 'Parentheses cannot be empty' , async ( ) => {
215+ await expect ( codeAnalyzer . selectRules ( [ '()' ] ) ) . rejects . toThrow ( 'empty' ) ;
216+ } ) ;
217+
218+ it ( 'Redundant parentheses are accepted' , async ( ) => {
219+ const selection : RuleSelection = await codeAnalyzer . selectRules ( [ '((((((((stub1RuleC))))))))' ] ) ;
220+
221+ expect ( selection . getEngineNames ( ) ) . toEqual ( [ 'stubEngine1' ] ) ;
222+ expect ( ruleNamesFor ( selection , 'stubEngine1' ) ) . toEqual ( [ 'stub1RuleC' ] ) ;
223+ } )
224+
225+ it . each ( [
226+ { selector : 'a,b)' } ,
227+ { selector : '(a,b' } ,
228+ { selector : '((a,b)' } ,
229+ { selector : '(a),b)' } ,
230+ { selector : ')a,b)' } ,
231+ { selector : 'a,b(' }
232+ ] ) ( 'When parentheses are unbalanced, an error is thrown. Case: $selector' , async ( { selector} ) => {
233+ await expect ( codeAnalyzer . selectRules ( [ selector ] ) ) . rejects . toThrow ( 'looks incorrect' ) ;
234+ } ) ;
235+
236+ it . each ( [
237+ { selector : '2(a,b)' } ,
238+ { selector : '(a,b)2' } ,
239+ { selector : '2(a:b)' } ,
240+ { selector : '(a:b)2' }
241+ ] ) ( 'When parentheses are not accompanied by valid joiners, an error is thrown. Case: $selector' , async ( { selector} ) => {
242+ await expect ( codeAnalyzer . selectRules ( [ selector ] ) ) . rejects . toThrow ( 'looks incorrect' ) ;
243+ } ) ;
244+
245+
175246 it ( 'When selecting rules based on severity names instead of severity number, then we correctly return the rules' , async ( ) => {
176247 const selection : RuleSelection = await codeAnalyzer . selectRules ( [ 'High' , 'Recommended:Low' ] ) ;
177248
0 commit comments