@@ -212,4 +212,269 @@ describe('Keyphrase Checker Action', () => {
212212 "Exactly one of 'text-file' or 'text' inputs must be provided"
213213 )
214214 } )
215+
216+ // Tests for maximum-occurrences feature
217+ test ( 'passes when occurrences are within maximum limit' , async ( ) => {
218+ // Get the path to the test file
219+ const testFilePath = path . join ( __dirname , 'test-two-occurrences.md' )
220+
221+ // Setup mocks
222+ core . getInput . mockImplementation ( ( name ) => {
223+ switch ( name ) {
224+ case 'text-file' :
225+ return testFilePath
226+ case 'keyphrase' :
227+ return 'GitHub'
228+ case 'minimum-occurrences' :
229+ return '1'
230+ case 'maximum-occurrences' :
231+ return '3'
232+ default :
233+ return ''
234+ }
235+ } )
236+ core . getBooleanInput . mockReturnValue ( true )
237+
238+ // Run the action
239+ await run ( )
240+
241+ // Check expectations
242+ expect ( core . setOutput ) . toHaveBeenCalledWith ( 'occurrences' , 2 )
243+ expect ( core . setFailed ) . not . toHaveBeenCalled ( )
244+ } )
245+
246+ test ( 'fails when occurrences exceed maximum limit' , async ( ) => {
247+ // Get the path to the test file
248+ const testFilePath = path . join ( __dirname , 'test-two-occurrences.md' )
249+
250+ // Setup mocks
251+ core . getInput . mockImplementation ( ( name ) => {
252+ switch ( name ) {
253+ case 'text-file' :
254+ return testFilePath
255+ case 'keyphrase' :
256+ return 'GitHub'
257+ case 'minimum-occurrences' :
258+ return '1'
259+ case 'maximum-occurrences' :
260+ return '1'
261+ default :
262+ return ''
263+ }
264+ } )
265+ core . getBooleanInput . mockReturnValue ( true )
266+
267+ // Run the action
268+ await run ( )
269+
270+ // Check expectations
271+ expect ( core . setOutput ) . toHaveBeenCalledWith ( 'occurrences' , 2 )
272+ expect ( core . setFailed ) . toHaveBeenCalledWith (
273+ 'Expected at most 1 occurrences of "GitHub", but found 2'
274+ )
275+ } )
276+
277+ test ( 'passes with exact occurrences when min equals max' , async ( ) => {
278+ // Get the path to the test file
279+ const testFilePath = path . join ( __dirname , 'test-two-occurrences.md' )
280+
281+ // Setup mocks
282+ core . getInput . mockImplementation ( ( name ) => {
283+ switch ( name ) {
284+ case 'text-file' :
285+ return testFilePath
286+ case 'keyphrase' :
287+ return 'GitHub'
288+ case 'minimum-occurrences' :
289+ return '2'
290+ case 'maximum-occurrences' :
291+ return '2'
292+ default :
293+ return ''
294+ }
295+ } )
296+ core . getBooleanInput . mockReturnValue ( true )
297+
298+ // Run the action
299+ await run ( )
300+
301+ // Check expectations
302+ expect ( core . setOutput ) . toHaveBeenCalledWith ( 'occurrences' , 2 )
303+ expect ( core . setFailed ) . not . toHaveBeenCalled ( )
304+ } )
305+
306+ test ( 'fails when maximum is less than minimum' , async ( ) => {
307+ // Get the path to the test file
308+ const testFilePath = path . join ( __dirname , 'test-two-occurrences.md' )
309+
310+ // Setup mocks
311+ core . getInput . mockImplementation ( ( name ) => {
312+ switch ( name ) {
313+ case 'text-file' :
314+ return testFilePath
315+ case 'keyphrase' :
316+ return 'GitHub'
317+ case 'minimum-occurrences' :
318+ return '3'
319+ case 'maximum-occurrences' :
320+ return '2'
321+ default :
322+ return ''
323+ }
324+ } )
325+ core . getBooleanInput . mockReturnValue ( true )
326+
327+ // Run the action
328+ await run ( )
329+
330+ // Check expectations
331+ expect ( core . setFailed ) . toHaveBeenCalledWith (
332+ 'Invalid configuration: maximum-occurrences (2) must be greater than or equal to minimum-occurrences (3)'
333+ )
334+ } )
335+
336+ test ( 'passes with range validation - occurrences within range' , async ( ) => {
337+ // Get the path to the test file with mixed case occurrences (3 total)
338+ const testFilePath = path . join ( __dirname , 'test-mixed-case.md' )
339+
340+ // Setup mocks
341+ core . getInput . mockImplementation ( ( name ) => {
342+ switch ( name ) {
343+ case 'text-file' :
344+ return testFilePath
345+ case 'keyphrase' :
346+ return 'GitHub'
347+ case 'minimum-occurrences' :
348+ return '2'
349+ case 'maximum-occurrences' :
350+ return '5'
351+ default :
352+ return ''
353+ }
354+ } )
355+ core . getBooleanInput . mockReturnValue ( false )
356+
357+ // Run the action
358+ await run ( )
359+
360+ // Check expectations
361+ expect ( core . setOutput ) . toHaveBeenCalledWith ( 'occurrences' , 3 )
362+ expect ( core . setFailed ) . not . toHaveBeenCalled ( )
363+ } )
364+
365+ test ( 'fails when occurrences are below minimum in range validation' , async ( ) => {
366+ // Get the path to the test file
367+ const testFilePath = path . join ( __dirname , 'test-two-occurrences.md' )
368+
369+ // Setup mocks
370+ core . getInput . mockImplementation ( ( name ) => {
371+ switch ( name ) {
372+ case 'text-file' :
373+ return testFilePath
374+ case 'keyphrase' :
375+ return 'GitHub'
376+ case 'minimum-occurrences' :
377+ return '3'
378+ case 'maximum-occurrences' :
379+ return '5'
380+ default :
381+ return ''
382+ }
383+ } )
384+ core . getBooleanInput . mockReturnValue ( true )
385+
386+ // Run the action
387+ await run ( )
388+
389+ // Check expectations
390+ expect ( core . setOutput ) . toHaveBeenCalledWith ( 'occurrences' , 2 )
391+ expect ( core . setFailed ) . toHaveBeenCalledWith (
392+ 'Expected at least 3 occurrences of "GitHub", but found only 2'
393+ )
394+ } )
395+
396+ test ( 'fails when occurrences are above maximum in range validation' , async ( ) => {
397+ // Get the path to the test file with mixed case occurrences (3 total)
398+ const testFilePath = path . join ( __dirname , 'test-mixed-case.md' )
399+
400+ // Setup mocks
401+ core . getInput . mockImplementation ( ( name ) => {
402+ switch ( name ) {
403+ case 'text-file' :
404+ return testFilePath
405+ case 'keyphrase' :
406+ return 'GitHub'
407+ case 'minimum-occurrences' :
408+ return '1'
409+ case 'maximum-occurrences' :
410+ return '2'
411+ default :
412+ return ''
413+ }
414+ } )
415+ core . getBooleanInput . mockReturnValue ( false )
416+
417+ // Run the action
418+ await run ( )
419+
420+ // Check expectations
421+ expect ( core . setOutput ) . toHaveBeenCalledWith ( 'occurrences' , 3 )
422+ expect ( core . setFailed ) . toHaveBeenCalledWith (
423+ 'Expected at most 2 occurrences of "GitHub", but found 3'
424+ )
425+ } )
426+
427+ test ( 'works with maximum-occurrences set to 0' , async ( ) => {
428+ // Setup mocks for text without the keyphrase
429+ core . getInput . mockImplementation ( ( name ) => {
430+ switch ( name ) {
431+ case 'text' :
432+ return 'This text does not contain the searched term'
433+ case 'keyphrase' :
434+ return 'GitHub'
435+ case 'minimum-occurrences' :
436+ return '0'
437+ case 'maximum-occurrences' :
438+ return '0'
439+ default :
440+ return ''
441+ }
442+ } )
443+ core . getBooleanInput . mockReturnValue ( true )
444+
445+ // Run the action
446+ await run ( )
447+
448+ // Check expectations
449+ expect ( core . setOutput ) . toHaveBeenCalledWith ( 'occurrences' , 0 )
450+ expect ( core . setFailed ) . not . toHaveBeenCalled ( )
451+ } )
452+
453+ test ( 'fails when maximum-occurrences is 0 but keyphrase is found' , async ( ) => {
454+ // Setup mocks
455+ core . getInput . mockImplementation ( ( name ) => {
456+ switch ( name ) {
457+ case 'text' :
458+ return 'This text contains GitHub'
459+ case 'keyphrase' :
460+ return 'GitHub'
461+ case 'minimum-occurrences' :
462+ return '0'
463+ case 'maximum-occurrences' :
464+ return '0'
465+ default :
466+ return ''
467+ }
468+ } )
469+ core . getBooleanInput . mockReturnValue ( true )
470+
471+ // Run the action
472+ await run ( )
473+
474+ // Check expectations
475+ expect ( core . setOutput ) . toHaveBeenCalledWith ( 'occurrences' , 1 )
476+ expect ( core . setFailed ) . toHaveBeenCalledWith (
477+ 'Expected at most 0 occurrences of "GitHub", but found 1'
478+ )
479+ } )
215480} )
0 commit comments