4
4
using System . Diagnostics ;
5
5
using System . IO ;
6
6
using System . Linq ;
7
- using System . Reflection ;
8
7
using System . Runtime . InteropServices ;
9
8
using System . Threading ;
10
9
using Microsoft . VisualStudio . TestPlatform . ObjectModel ;
@@ -608,19 +607,19 @@ void handler()
608
607
}
609
608
610
609
public static IRunnerReporter GetRunnerReporter (
611
- LoggerHelper logger ,
610
+ LoggerHelper ? logger ,
612
611
RunSettings runSettings ,
613
612
IReadOnlyList < string > assemblyFileNames )
614
613
{
615
614
var reporter = default ( IRunnerReporter ) ;
616
- var availableReporters = new Lazy < IReadOnlyList < IRunnerReporter > > ( ( ) => GetAvailableRunnerReporters ( assemblyFileNames ) ) ;
615
+ var availableReporters = new Lazy < IReadOnlyList < IRunnerReporter > > ( ( ) => GetAvailableRunnerReporters ( logger , assemblyFileNames ) ) ;
617
616
618
617
try
619
618
{
620
619
if ( ! string . IsNullOrEmpty ( runSettings . ReporterSwitch ) )
621
620
{
622
621
reporter = availableReporters . Value . FirstOrDefault ( r => string . Equals ( r . RunnerSwitch , runSettings . ReporterSwitch , StringComparison . OrdinalIgnoreCase ) ) ;
623
- if ( reporter is null )
622
+ if ( reporter is null && logger is not null )
624
623
logger . LogWarning ( "Could not find requested reporter '{0}'" , runSettings . ReporterSwitch ) ;
625
624
}
626
625
@@ -632,119 +631,30 @@ public static IRunnerReporter GetRunnerReporter(
632
631
return reporter ?? new DefaultRunnerReporterWithTypes ( ) ;
633
632
}
634
633
635
- static IReadOnlyList < IRunnerReporter > GetAvailableRunnerReporters ( IReadOnlyList < string > sources )
634
+ public static IReadOnlyList < IRunnerReporter > GetAvailableRunnerReporters (
635
+ LoggerHelper ? logger ,
636
+ IReadOnlyList < string > sources )
636
637
{
637
- #if NETCOREAPP
638
- // Combine all input libs and merge their contexts to find the potential reporters
639
638
var result = new List < IRunnerReporter > ( ) ;
640
- var dcjr = new DependencyContextJsonReader ( ) ;
641
- var deps =
642
- sources
643
- . Select ( Path . GetFullPath )
644
- . Select ( s => s . Replace ( ".dll" , ".deps.json" ) )
645
- . Where ( File . Exists )
646
- . Select ( f => new MemoryStream ( Encoding . UTF8 . GetBytes ( File . ReadAllText ( f ) ) ) )
647
- . Select ( dcjr . Read ) ;
648
- var ctx = deps . Aggregate ( DependencyContext . Default , ( context , dependencyContext ) => context . Merge ( dependencyContext ) ) ;
649
- dcjr . Dispose ( ) ;
650
-
651
- var depsAssms = ctx . GetRuntimeAssemblyNames ( InternalRuntimeEnvironment . GetRuntimeIdentifier ( ) ) . ToList ( ) ;
652
-
653
- // Make sure to also check assemblies within the directory of the sources
654
- var dllsInSources =
639
+
640
+ // We need to combine the source folders with our folder to find all potential runners
641
+ var folders =
655
642
sources
656
- . Select ( Path . GetFullPath )
657
- . Select ( Path . GetDirectoryName )
658
- . Distinct ( StringComparer . OrdinalIgnoreCase )
643
+ . Select ( s => Path . GetDirectoryName ( Path . GetFullPath ( s ) ) )
659
644
. WhereNotNull ( )
660
- . SelectMany ( p => Directory . GetFiles ( p , "*.dll" ) . Select ( f => Path . Combine ( p , f ) ) )
661
- . Select ( f => new AssemblyName { Name = Path . GetFileNameWithoutExtension ( f ) } )
662
- . ToList ( ) ;
645
+ . Concat ( new [ ] { Path . GetDirectoryName ( typeof ( VsTestRunner ) . Assembly . GetLocalCodeBase ( ) ) } )
646
+ . Distinct ( ) ;
663
647
664
- foreach ( var assemblyName in depsAssms . Concat ( dllsInSources ) )
648
+ foreach ( var folder in folders )
665
649
{
666
- try
667
- {
668
- var assembly = Assembly . Load ( assemblyName ) ;
669
- foreach ( var type in assembly . DefinedTypes )
670
- {
671
- #pragma warning disable CS0618
672
- if ( type == null || type . IsAbstract || type == typeof ( DefaultRunnerReporter ) . GetTypeInfo ( ) || type == typeof ( DefaultRunnerReporterWithTypes ) . GetTypeInfo ( ) || type . ImplementedInterfaces . All ( i => i != typeof ( IRunnerReporter ) ) )
673
- continue ;
674
- #pragma warning restore CS0618
675
-
676
- var ctor = type . DeclaredConstructors . FirstOrDefault ( c => c . GetParameters ( ) . Length == 0 ) ;
677
- if ( ctor == null )
678
- {
679
- ConsoleHelper . SetForegroundColor ( ConsoleColor . Yellow ) ;
680
- Console . WriteLine ( $ "Type { type . FullName } in assembly { assembly } appears to be a runner reporter, but does not have an empty constructor.") ;
681
- ConsoleHelper . ResetColor ( ) ;
682
- continue ;
683
- }
650
+ result . AddRange ( RunnerReporterUtility . GetAvailableRunnerReporters ( folder , out var messages ) ) ;
684
651
685
- result . Add ( ( IRunnerReporter ) ctor . Invoke ( Array . Empty < object > ( ) ) ) ;
686
- }
687
- }
688
- catch
689
- {
690
- continue ;
691
- }
652
+ if ( logger is not null )
653
+ foreach ( var message in messages )
654
+ logger . LogWarning ( message ) ;
692
655
}
693
656
694
657
return result ;
695
- #else
696
- var result = new List < IRunnerReporter > ( ) ;
697
- var runnerPath = Path . GetDirectoryName ( Assembly . GetExecutingAssembly ( ) . GetLocalCodeBase ( ) ) ;
698
- var runnerReporterInterfaceAssemblyFullName = typeof ( IRunnerReporter ) . Assembly . GetName ( ) . FullName ;
699
-
700
- if ( runnerPath != null )
701
- foreach ( var dllFile in Directory . GetFiles ( runnerPath , "*.dll" ) . Select ( f => Path . Combine ( runnerPath , f ) ) )
702
- {
703
- Type ? [ ] types ;
704
-
705
- try
706
- {
707
- var assembly = Assembly . LoadFile ( dllFile ) ;
708
-
709
- // Calling Assembly.GetTypes can be very expensive, while Assembly.GetReferencedAssemblies
710
- // is relatively cheap. We can avoid loading types for assemblies that couldn't possibly
711
- // reference IRunnerReporter.
712
- if ( ! assembly . GetReferencedAssemblies ( ) . Where ( name => name . FullName == runnerReporterInterfaceAssemblyFullName ) . Any ( ) )
713
- continue ;
714
-
715
- types = assembly . GetTypes ( ) ;
716
- }
717
- catch ( ReflectionTypeLoadException ex )
718
- {
719
- types = ex . Types ;
720
- }
721
- catch
722
- {
723
- continue ;
724
- }
725
-
726
- foreach ( var type in types )
727
- {
728
- #pragma warning disable CS0618
729
- if ( type == null || type . IsAbstract || type == typeof ( DefaultRunnerReporter ) || type == typeof ( DefaultRunnerReporterWithTypes ) || ! type . GetInterfaces ( ) . Any ( t => t == typeof ( IRunnerReporter ) ) )
730
- continue ;
731
- #pragma warning restore CS0618
732
-
733
- var ctor = type . GetConstructor ( new Type [ 0 ] ) ;
734
- if ( ctor == null )
735
- {
736
- ConsoleHelper . SetForegroundColor ( ConsoleColor . Yellow ) ;
737
- Console . WriteLine ( $ "Type { type . FullName } in assembly { dllFile } appears to be a runner reporter, but does not have an empty constructor.") ;
738
- ConsoleHelper . ResetColor ( ) ;
739
- continue ;
740
- }
741
-
742
- result . Add ( ( IRunnerReporter ) ctor . Invoke ( new object [ 0 ] ) ) ;
743
- }
744
- }
745
-
746
- return result ;
747
- #endif
748
658
}
749
659
750
660
static IList < DiscoveredTestCase > GetVsTestCases (
0 commit comments