@@ -318,6 +318,284 @@ static void Main(string[] args)
318318 await VerifyCS . VerifyAnalyzerAsync ( source ) ;
319319 }
320320
321+ [ Fact ]
322+ public async Task ActionRouteToken_DifferentActionNames_NoDiagnostics ( )
323+ {
324+ // Arrange
325+ var source = @"
326+ using Microsoft.AspNetCore.Builder;
327+ using Microsoft.AspNetCore.Mvc;
328+ public class WeatherForecastController : ControllerBase
329+ {
330+ [Route(""{action}"")]
331+ public object Get() => new object();
332+
333+ [Route(""{action}"")]
334+ public object Get1() => new object();
335+ }
336+ internal class Program
337+ {
338+ static void Main(string[] args)
339+ {
340+ }
341+ }
342+ " ;
343+
344+ // Act & Assert
345+ await VerifyCS . VerifyAnalyzerAsync ( source ) ;
346+ }
347+
348+ [ Fact ]
349+ public async Task ActionRouteToken_SameActionName_HasDiagnostics ( )
350+ {
351+ // Arrange
352+ var source = @"
353+ using Microsoft.AspNetCore.Builder;
354+ using Microsoft.AspNetCore.Mvc;
355+ public class WeatherForecastController : ControllerBase
356+ {
357+ [Route({|#0:""{action}""|})]
358+ public object Get() => new object();
359+
360+ [Route({|#1:""{action}""|})]
361+ public object Get(int i) => new object();
362+ }
363+ internal class Program
364+ {
365+ static void Main(string[] args)
366+ {
367+ }
368+ }
369+ " ;
370+
371+ var expectedDiagnostics = new [ ] {
372+ new DiagnosticResult ( DiagnosticDescriptors . AmbiguousActionRoute ) . WithArguments ( "{action}" ) . WithLocation ( 0 ) ,
373+ new DiagnosticResult ( DiagnosticDescriptors . AmbiguousActionRoute ) . WithArguments ( "{action}" ) . WithLocation ( 1 )
374+ } ;
375+
376+ // Act & Assert
377+ await VerifyCS . VerifyAnalyzerAsync ( source , expectedDiagnostics ) ;
378+ }
379+
380+ [ Fact ]
381+ public async Task ActionRouteToken_ActionNameAttribute_HasDiagnostics ( )
382+ {
383+ // Arrange
384+ var source = @"
385+ using Microsoft.AspNetCore.Builder;
386+ using Microsoft.AspNetCore.Mvc;
387+ public class WeatherForecastController : ControllerBase
388+ {
389+ [Route({|#0:""{action}""|})]
390+ public object Get() => new object();
391+
392+ [Route({|#1:""{action}""|})]
393+ [ActionName(""get"")]
394+ public object Get1(int i) => new object();
395+ }
396+ internal class Program
397+ {
398+ static void Main(string[] args)
399+ {
400+ }
401+ }
402+ " ;
403+
404+ var expectedDiagnostics = new [ ] {
405+ new DiagnosticResult ( DiagnosticDescriptors . AmbiguousActionRoute ) . WithArguments ( "{action}" ) . WithLocation ( 0 ) ,
406+ new DiagnosticResult ( DiagnosticDescriptors . AmbiguousActionRoute ) . WithArguments ( "{action}" ) . WithLocation ( 1 )
407+ } ;
408+
409+ // Act & Assert
410+ await VerifyCS . VerifyAnalyzerAsync ( source , expectedDiagnostics ) ;
411+ }
412+
413+ [ Fact ]
414+ public async Task ActionRouteToken_ActionNameAttributeNullValue_NoDiagnostics ( )
415+ {
416+ // Arrange
417+ var source = @"
418+ using Microsoft.AspNetCore.Builder;
419+ using Microsoft.AspNetCore.Mvc;
420+ public class WeatherForecastController : ControllerBase
421+ {
422+ [Route({|#0:""{action}""|})]
423+ public object Get() => new object();
424+
425+ [Route({|#1:""{action}""|})]
426+ [ActionName(null)]
427+ public object Get1(int i) => new object();
428+ }
429+ internal class Program
430+ {
431+ static void Main(string[] args)
432+ {
433+ }
434+ }
435+ " ;
436+
437+ // Act & Assert
438+ await VerifyCS . VerifyAnalyzerAsync ( source ) ;
439+ }
440+
441+ [ Fact ]
442+ public async Task ActionRouteToken_OnController_NoDiagnostics ( )
443+ {
444+ // Arrange
445+ var source = @"
446+ using Microsoft.AspNetCore.Builder;
447+ using Microsoft.AspNetCore.Mvc;
448+ [Route(""{controller}/{action}"")]
449+ public class WeatherForecastController : ControllerBase
450+ {
451+ [Route(""{i}"")]
452+ public object Get(int i) => new object();
453+
454+ [Route(""{i}"")]
455+ public object Get1(int i) => new object();
456+ }
457+ internal class Program
458+ {
459+ static void Main(string[] args)
460+ {
461+ }
462+ }
463+ " ;
464+
465+ // Act & Assert
466+ await VerifyCS . VerifyAnalyzerAsync ( source ) ;
467+ }
468+
469+ [ Fact ]
470+ public async Task ActionRouteToken_OnBaseController_NoDiagnostics ( )
471+ {
472+ // Arrange
473+ var source = @"
474+ using Microsoft.AspNetCore.Builder;
475+ using Microsoft.AspNetCore.Mvc;
476+ [Route(""{controller}/{action}"")]
477+ public class MyControllerBase : ControllerBase
478+ {
479+ }
480+ public class WeatherForecastController : MyControllerBase
481+ {
482+ [Route(""{i}"")]
483+ public object Get(int i) => new object();
484+
485+ [Route(""{i}"")]
486+ public object Get1(int i) => new object();
487+ }
488+ internal class Program
489+ {
490+ static void Main(string[] args)
491+ {
492+ }
493+ }
494+ " ;
495+
496+ // Act & Assert
497+ await VerifyCS . VerifyAnalyzerAsync ( source ) ;
498+ }
499+
500+ [ Fact ]
501+ public async Task ActionRouteToken_OnBaseControllerButOverridden_HasDiagnostics ( )
502+ {
503+ // Arrange
504+ var source = @"
505+ using Microsoft.AspNetCore.Builder;
506+ using Microsoft.AspNetCore.Mvc;
507+ [Route(""{controller}/{action}"")]
508+ public class MyControllerBase : ControllerBase
509+ {
510+ }
511+ [Route(""api"")]
512+ public class WeatherForecastController : MyControllerBase
513+ {
514+ [Route({|#0:""{i}""|})]
515+ public object Get(int i) => new object();
516+
517+ [Route({|#1:""{i}""|})]
518+ public object Get1(int i) => new object();
519+ }
520+ internal class Program
521+ {
522+ static void Main(string[] args)
523+ {
524+ }
525+ }
526+ " ;
527+
528+ var expectedDiagnostics = new [ ] {
529+ new DiagnosticResult ( DiagnosticDescriptors . AmbiguousActionRoute ) . WithArguments ( "{i}" ) . WithLocation ( 0 ) ,
530+ new DiagnosticResult ( DiagnosticDescriptors . AmbiguousActionRoute ) . WithArguments ( "{i}" ) . WithLocation ( 1 )
531+ } ;
532+
533+ // Act & Assert
534+ await VerifyCS . VerifyAnalyzerAsync ( source , expectedDiagnostics ) ;
535+ }
536+
537+ [ Fact ]
538+ public async Task ActionRouteToken_OnController_ActionName_NoDiagnostics ( )
539+ {
540+ // Arrange
541+ var source = @"
542+ using Microsoft.AspNetCore.Builder;
543+ using Microsoft.AspNetCore.Mvc;
544+ [Route(""{controller}/{action}"")]
545+ public class WeatherForecastController : ControllerBase
546+ {
547+ [Route(""{i}"")]
548+ public object Get(int i) => new object();
549+
550+ [Route(""{s}"")]
551+ [ActionName(name: ""getWithString"")]
552+ public object Get(string s) => new object();
553+ }
554+ internal class Program
555+ {
556+ static void Main(string[] args)
557+ {
558+ }
559+ }
560+ " ;
561+
562+ // Act & Assert
563+ await VerifyCS . VerifyAnalyzerAsync ( source ) ;
564+ }
565+
566+ [ Fact ]
567+ public async Task ActionRouteToken_OnController_ActionNameOnBase_NoDiagnostics ( )
568+ {
569+ // Arrange
570+ var source = @"
571+ using Microsoft.AspNetCore.Builder;
572+ using Microsoft.AspNetCore.Mvc;
573+ public abstract class MyControllerBase : ControllerBase
574+ {
575+ [ActionName(name: ""getWithString"")]
576+ public abstract object Get(string s);
577+ }
578+ [Route(""{controller}/{action}"")]
579+ public class WeatherForecastController : MyControllerBase
580+ {
581+ [Route(""{i}"")]
582+ public object Get(int i) => new object();
583+
584+ [Route(""{s}"")]
585+ public override object Get(string s) => new object();
586+ }
587+ internal class Program
588+ {
589+ static void Main(string[] args)
590+ {
591+ }
592+ }
593+ " ;
594+
595+ // Act & Assert
596+ await VerifyCS . VerifyAnalyzerAsync ( source ) ;
597+ }
598+
321599 [ Fact ]
322600 public async Task MixedRoutes_DifferentAction_HasDiagnostics ( )
323601 {
0 commit comments