public void AllDatabaseEntitiesHaveTypedIRepository() { SetupMEF(); List <string> problems = new List <string>(); foreach (var type in MEF.GetAllTypes().Where(t => typeof(DatabaseEntity).IsAssignableFrom(t))) { foreach (var constructorInfo in type.GetConstructors()) { var parameters = constructorInfo.GetParameters(); if (parameters.Any(p => p.ParameterType == typeof(IRepository))) { problems.Add($"Constructor found on Type {type} that takes {nameof(IRepository)}, it should take either {nameof(IDataExportRepository)} or {nameof(ICatalogueRepository)}"); } } } foreach (var problem in problems) { TestContext.Out.WriteLine(problem); } Assert.IsEmpty(problems); }
private void Initialize() { initialized = true; //get all the SecondaryConstraints foreach (Type constraintType in _mef.GetAllTypes().Where(c => typeof(ISecondaryConstraint).IsAssignableFrom(c))) { //get all properties and fields which map to a database object var props = constraintType.GetProperties().Where(p => typeof(IMapsDirectlyToDatabaseTable).IsAssignableFrom(p.PropertyType)).ToList(); var fields = constraintType.GetFields().Where(f => typeof(IMapsDirectlyToDatabaseTable).IsAssignableFrom(f.FieldType)).ToList(); //there are no suspect fields that could have hidden dependencies if (!props.Any() && !fields.Any()) { continue; } string constraintName = constraintType.Name; string pattern = Regex.Escape("<SecondaryConstraint xsi:type=\"" + constraintName + "\">"); //anything pattern += ".*"; //this will be replaced by the ID of the thing we are deleting (dont match 1 to 115 though!) pattern += @"\b{0}\b"; //then more of anything pattern += ".*"; //then the end of the secondary constraint pattern += Regex.Escape("</SecondaryConstraint>"); TheUsualSuspects.Add(new Suspect(pattern, constraintType, props, fields)); } }
private IEnumerable <string> EnforceTypeBelongsInNamespace(Type InterfaceType, params string[] legalNamespaces) { SetupMEF(); foreach (Type type in MEF.GetAllTypes().Where(InterfaceType.IsAssignableFrom)) { if (type.Namespace == null) { continue; } //don't validate classes in testing code if (type.Namespace.Contains(".Tests")) { continue; } //theese guys can be wherever they want if (_exemptNamespaces.Any(e => type.Namespace.Contains(e))) { continue; } if (!legalNamespaces.Any(ns => type.Namespace.Contains(ns))) { yield return("Expected Type '" + type.Name + "' to be in namespace(s) '" + string.Join("' or '", legalNamespaces) + "' but it was in '" + type.Namespace + "'"); } evaluatedClasses++; } Console.WriteLine("Evaluated " + evaluatedClasses + " classes for namespace compatibility"); }
/// <summary> /// Lists assembly load errors and attempts to construct instances of all Types declared as Exports (which are ICheckable) /// </summary> /// <param name="notifier"></param> public void Check(ICheckNotifier notifier) { foreach (KeyValuePair <string, Exception> badAssembly in _mefPlugins.ListBadAssemblies()) { notifier.OnCheckPerformed(new CheckEventArgs("Could not load assembly " + badAssembly.Key, CheckResult.Fail, badAssembly.Value)); } foreach (Type t in _mefPlugins.GetAllTypes()) { notifier.OnCheckPerformed(new CheckEventArgs("Found Type " + t, CheckResult.Success, null)); if (typeof(ICheckable).IsAssignableFrom(t)) { try { _mefPlugins.CreateA <ICheckable>(t.FullName); } catch (Exception ex) { notifier.OnCheckPerformed(new CheckEventArgs( "Class " + t.FullName + " implements ICheckable but could not be created as an ICheckable.", CheckResult.Warning, ex)); } } } }
public void FindProblems(MEF mef) { List <string> excusables = new List <string>() { "IPlugin", "IDataAccessCredentials", "IProcessTask" //this is inherited by IRuntimeTask too which isn't an IMapsDirectlyToDatabaseTable }; List <string> problems = new List <string>(); foreach (var dbEntities in mef.GetAllTypes().Where(t => typeof(DatabaseEntity).IsAssignableFrom(t))) { var matchingInterface = typeof(Catalogue).Assembly.GetTypes().SingleOrDefault(t => t.Name.Equals("I" + dbEntities.Name)); if (matchingInterface != null) { if (excusables.Contains(matchingInterface.Name)) { continue; } if (!typeof(IMapsDirectlyToDatabaseTable).IsAssignableFrom(matchingInterface)) { problems.Add("FAIL: Interface '" + matchingInterface.Name + "' does not inherit IMapsDirectlyToDatabaseTable"); } } } foreach (string problem in problems) { Console.WriteLine(problem); } Assert.AreEqual(0, problems.Count); }
public void GetRepositoryConstructor_AllDatabaseEntities_OneWinningConstructor() { SetupMEF(); int countCompatible = 0; var badTypes = new Dictionary <Type, Exception>(); foreach (Type t in MEF.GetAllTypes().Where(typeof(DatabaseEntity).IsAssignableFrom)) { try { var oc = new ObjectConstructor(); Assert.IsNotNull(oc.GetRepositoryConstructor(typeof(Catalogue))); countCompatible++; } catch (Exception e) { badTypes.Add(t, e); } } Assert.IsEmpty(badTypes); Assert.GreaterOrEqual(countCompatible, 10); Console.WriteLine("Found compatible constructors on " + countCompatible + " objects"); }
public void Check(ICheckNotifier notifier) { foreach (Type t in _mef.GetAllTypes().Where(t => typeof(DatabaseEntity).IsAssignableFrom(t))) { if (typeof(IMapsDirectlyToDatabaseTable).IsAssignableFrom(t)) { if (t.IsInterface || t.IsAbstract || t.Name.StartsWith("Spontaneous")) { continue; } try { //spontaneous objects don't exist in the database. if (typeof(SpontaneousObject).IsAssignableFrom(t)) { continue; } } catch (Exception) { continue; } notifier.OnCheckPerformed(new CheckEventArgs("Found type " + t, CheckResult.Success)); var docs = _commentStore.GetTypeDocumentationIfExists(t, true, true); if (docs == null) { notifier.OnCheckPerformed( new CheckEventArgs("Failed to get definition for class " + t.FullName, CheckResult.Fail)); } else { Summaries.Add(t, docs); } } } }
public void FindProblems(List <string> csFilesList, MEF mef) { _csFilesList = csFilesList; //All node classes should have equality compare members so that tree expansion works properly foreach (Type nodeClass in mef.GetAllTypes().Where(t => typeof(Node).IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface)) { if (nodeClass.Namespace == null || nodeClass.Namespace.StartsWith("System")) { continue; } //class is excused if (excusedNodeClasses.Contains(nodeClass)) { continue; } //it's something like ProposeExecutionWhenTargetIsIDirectoryNode.cs i.e. it's not a Node! if (typeof(ICommandExecutionProposal).IsAssignableFrom(nodeClass)) { continue; } //if it's an ObjectUsedByOtherObjectNode then it will already have GetHashCode implemented if (typeof(IObjectUsedByOtherObjectNode).IsAssignableFrom(nodeClass)) { continue; } if (typeof(ExtractionArbitraryFolderNode).IsAssignableFrom(nodeClass)) { continue; } //these are all supported at base class level if (typeof(SingletonNode).IsAssignableFrom(nodeClass)) { if (!nodeClass.Name.StartsWith("All")) { problems.Add("Class '" + nodeClass.Name + "' is a SingletonNode but it's name doesn't start with All"); } continue; } ConfirmFileHasText(nodeClass, "public override int GetHashCode()"); } //All Menus should correspond to a data class foreach (Type menuClass in mef.GetAllTypes().Where(t => typeof(RDMPContextMenuStrip).IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface)) { if (menuClass == typeof(RDMPContextMenuStrip)) //the basic class from which all are inherited { continue; } //We are looking at something like AutomationServerSlotsMenu if (!menuClass.Name.EndsWith("Menu")) { problems.Add("Class '" + menuClass + "' is a RDMPContextMenuStrip but it's name doesn't end with Menu"); continue; } foreach (ConstructorInfo c in menuClass.GetConstructors()) { if (c.GetParameters().Count() != 2) { problems.Add("Constructor of class '" + menuClass + "' which is an RDMPContextMenuStrip contained " + c.GetParameters().Count() + " constructor arguments. These menus are driven by reflection (See RDMPCollectionCommonFunctionality.GetMenuWithCompatibleConstructorIfExists )"); } } var toLookFor = menuClass.Name.Substring(0, menuClass.Name.Length - "Menu".Length); var expectedClassName = GetExpectedClassOrInterface(toLookFor); if (expectedClassName == null) { problems.Add("Found menu called '" + menuClass.Name + "' but couldn't find a corresponding data class called '" + toLookFor + ".cs'"); continue; } ConfirmFileHasText(menuClass, "AddCommonMenuItems()", false); //expect something like this //public AutomationServerSlotsMenu(IActivateItems activator, AllAutomationServerSlotsNode databaseEntity) string expectedConstructorSignature = menuClass.Name + "(RDMPContextMenuStripArgs args," + expectedClassName; ConfirmFileHasText(menuClass, expectedConstructorSignature); FieldInfo[] fields = menuClass.GetFields( BindingFlags.NonPublic | BindingFlags.Instance); //find private fields declared at the object level (i.e. not in base class that are of type IActivateItem) var activatorField = fields.FirstOrDefault(f => f.DeclaringType == menuClass && f.FieldType == typeof(IActivateItems)); if (activatorField != null) { problems.Add("Menu '" + menuClass + "' contains a private field called '" + activatorField.Name + "'. You should instead use base class protected field RDMPContextMenuStrip._activator"); } } //Drag and drop / Activation - Execution Proposal system foreach (Type proposalClass in mef.GetAllTypes().Where(t => typeof(ICommandExecutionProposal).IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface)) { if (proposalClass.Namespace.Contains("Rdmp.UI.Tests.DesignPatternTests")) { continue; } //We are looking at something like AutomationServerSlotsMenu if (!proposalClass.Name.StartsWith("ProposeExecutionWhenTargetIs")) { problems.Add("Class '" + proposalClass + "' is a ICommandExecutionProposal but it's name doesn't start with ProposeExecutionWhenTargetIs"); continue; } var toLookFor = proposalClass.Name.Substring("ProposeExecutionWhenTargetIs".Length); string expectedClassName = GetExpectedClassOrInterface(toLookFor); if (expectedClassName == null) { problems.Add("Found proposal called '" + proposalClass + "' but couldn't find a corresponding data class called '" + toLookFor + ".cs'"); } } //Make sure all user interface classes have the suffix UI foreach (Type uiType in mef.GetAllTypes().Where(t => (typeof(RDMPUserControl).IsAssignableFrom(t) || (typeof(RDMPForm).IsAssignableFrom(t)) && !t.IsAbstract && !t.IsInterface))) { if (!uiType.Name.EndsWith("UI") && !uiType.Name.EndsWith("_Design")) { if (excusedUIClasses.Contains(uiType)) { continue; } //also allow Screen1, Screen2 etc if (Regex.IsMatch(uiType.Name, @"Screen\d") && uiType.IsNotPublic) { continue; } problems.Add("Class " + uiType.Name + " does not end with UI"); } } foreach (string problem in problems) { Console.WriteLine("FATAL ERROR PROBLEM:" + problem); } Assert.AreEqual(problems.Count, 0); }
private void AnalyseRelationshipPropertyUsages() { foreach (var t in mef.GetAllTypes()) { if (!t.IsClass) { continue; } //don't worry about the ToString method on classes that are IInjectKnown var toStringMethod = t.GetMethod("ToString", new Type[0]); //it doesn't have any ToString methods! if (toStringMethod == null) { continue; } if (toStringMethod.DeclaringType == typeof(System.Object)) { continue; } if (toStringMethod.DeclaringType == typeof(MarshalByRefObject)) { continue; } /* * IList<Instruction> instructions = null; * try * { * instructions = toStringMethod.GetInstructions(); * } * catch (Exception e) * { * Console.WriteLine(e); * } * * if (instructions != null) * foreach (Instruction instruction in instructions) * { * MethodInfo methodInfo = instruction.Operand as MethodInfo; * * if (methodInfo != null) * { * //is it a call to property * PropertyInfo prop; * * if (RelationshipPropertyInfos.TryGetBySecond(methodInfo, out prop)) * { * * //It doesn't look injected but it is * if(t == typeof(JoinInfo)) * continue; * * //if we are injectable for it * if( t.GetInterfaces().Any(x => * x.IsGenericType && * x.GetGenericTypeDefinition() == typeof(IInjectKnown<>) && * x.GetGenericArguments()[0] == prop.PropertyType)) * continue; * * _fails.Add("FAIL: ToString method in Type " + t.FullName + " uses Relationship PropertyInfo " + prop.Name); * } * } * }*/ } }
/// <summary> /// Looks for the class name within the defined Types in all assemblies loaded in MEF. If you pass an ICheckNotifier which responds to ProposedFixes and the class /// is found under a different namespace (e.g. due to the coder of the plugin refactoring the class to a new location in his assembly) then the callback /// userAcceptedSubstitution will be invoked. Use AcceptAllCheckNotifier if you want the callback to always be called. /// </summary> /// <param name="notifier"></param> public void Check(ICheckNotifier notifier) { if (string.IsNullOrWhiteSpace(_classToFind)) { notifier.OnCheckPerformed(new CheckEventArgs( "MEFChecker was asked to check for the existence of an Export class but the _classToFind string was empty", CheckResult.Fail, null)); return; } string typeNameOnly = _classToFind.Substring(_classToFind.LastIndexOf(".") + 1); var allTypes = _mefPlugins.GetAllTypes().ToArray(); if (allTypes.Any(t => t.FullName.Equals(_classToFind))) { notifier.OnCheckPerformed(new CheckEventArgs( "Found MEF class " + _classToFind + "", CheckResult.Success, null)); } else { Type[] substitute = allTypes.Where(t => t.Name.Equals(typeNameOnly)).ToArray(); if (substitute.Length == 0) { notifier.OnCheckPerformed(new CheckEventArgs( "Could not find MEF class called " + _classToFind + " in LoadModuleAssembly.GetAllTypes() and couldn't even find any with the same basic name (Note that we only checked Exported MEF types e.g. classes implementing IPluginAttacher, IPluginDataProvider etc)", CheckResult.Fail, null)); Dictionary <string, Exception> badAssemblies = _mefPlugins.ListBadAssemblies(); if (badAssemblies.Any()) { notifier.OnCheckPerformed(new CheckEventArgs( "It is possible that the class you are looking for is in the BadAssemblies list", CheckResult.Fail, null)); } foreach (KeyValuePair <string, Exception> badAssembly in badAssemblies) { notifier.OnCheckPerformed(new CheckEventArgs("Bad Assembly " + badAssembly.Key, CheckResult.Warning, badAssembly.Value)); } } else if (substitute.Length == 1) { bool acceptSubstitution = notifier.OnCheckPerformed(new CheckEventArgs( "Could not find MEF class called " + _classToFind + " but did find one called " + substitute[0].FullName, CheckResult.Fail, null, "Change reference to " + _classToFind + " to point to MEF assembly type " + substitute[0].FullName)); if (acceptSubstitution) { _userAcceptedSubstitution(substitute[0].FullName); } } else { notifier.OnCheckPerformed(new CheckEventArgs( "Could not find MEF class called " + _classToFind + ", we were looking for a suitable replacment (a Type with the same basic name) but we found " + substitute.Length + " subistutitions!!! (" + substitute.Aggregate("", (s, n) => s + n.FullName + ","), CheckResult.Fail, null)); } } }
public void TestAllSupported() { //load all DatabaseEntity types MEF mef = new MEF(); mef.Setup(new SafeDirectoryCatalog(TestContext.CurrentContext.TestDirectory)); var types = mef.GetAllTypes() .Where(t => typeof(DatabaseEntity).IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface).ToArray(); var methods = typeof(UnitTests).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance); var method = methods.Single(m => m.Name.Equals("WhenIHaveA") && !m.GetParameters().Any()); List <Type> notSupported = new List <Type>(); foreach (Type t in types) { //ignore these types too if (SkipTheseTypes.Contains(t.Name) || t.Name.StartsWith("Spontaneous") || typeof(SpontaneousObject).IsAssignableFrom(t)) { continue; } DatabaseEntity instance = null; try { //ensure that the method supports the Type var generic = method.MakeGenericMethod(t); instance = (DatabaseEntity)generic.Invoke(this, null); } catch (TargetInvocationException exception) { if (exception.InnerException is TestCaseNotWrittenYetException) { notSupported.Add(t); } else { throw; } } //if the instance returned by MakeGenericMethod does not pass checks that's a dealbreaker! if (instance != null) { try { //and that it returns an instance Assert.IsNotNull(instance); Assert.IsTrue(instance.Exists()); Assert.AreEqual(ChangeDescription.NoChanges, instance.HasLocalChanges().Evaluation, "Type was '" + t.Name + "'"); } catch (Exception e) { throw new Exception("Implementation of WhenIHaveA<" + t.Name + "> is flawed", e); } } } Assert.IsEmpty(notSupported, "The following Types were not supported by WhenIHaveA<T>:" + Environment.NewLine + string.Join(Environment.NewLine, notSupported.Select(t => t.Name))); }