PluginLoader { @VisibleForTesting int comparePluginsByDependencyGraph(Class<? extends Plugin> p1, Class<? extends Plugin> p2) { if (requires(p1, p2)) { if (requires(p2, p1)) { throw new IllegalStateException( "Cyclical dependency detected! " + p1.getName() + " <-> " + p2.getName()); } return 1; } else if (requires(p2, p1)) { return -1; } else { return 0; } } PluginLoader(DataTypes dataTypes,
                      SourceTypes sourceTypes,
                      Components components,
                      Themes themes,
                      TabInfoRegistry tabInfoRegistry,
                      Converters converters,
                      PropertyParsers propertyParsers); static PluginLoader getDefault(); void loadAllJarsFromDir(Path directory); void loadPluginJar(URI jarUri); boolean loadPluginClass(Class<? extends Plugin> clazz); boolean load(Plugin plugin); boolean canLoad(Plugin plugin); @SuppressWarnings("unchecked") boolean unload(Plugin plugin); ObservableList<Plugin> getKnownPlugins(); ObservableSet<Plugin> getLoadedPlugins(); ObservableList<ClassLoader> getClassLoaders();  }
@Test public void testOrderPluginsNoDependencies() { assertEquals(0, loader.comparePluginsByDependencyGraph(MockPlugin.class, NewerVersionPlugin.class)); assertEquals(0, loader.comparePluginsByDependencyGraph(NewerVersionPlugin.class, MockPlugin.class)); }
@Test public void testOrderPluginsByDependencies() { assertEquals(1, loader.comparePluginsByDependencyGraph(DependentPlugin.class, MockPlugin.class)); assertEquals(-1, loader.comparePluginsByDependencyGraph(MockPlugin.class, DependentPlugin.class)); }
@Test public void testCyclicalDependencyThrows() { assertThrows(IllegalStateException.class, () -> loader.comparePluginsByDependencyGraph(CyclicalPluginA.class, CyclicalPluginB.class)); }
@Test public void testSelfDependencyThrows() { assertThrows(IllegalStateException.class, () -> loader.comparePluginsByDependencyGraph(SelfDependentPlugin.class, SelfDependentPlugin.class)); }