/** * Removes the given type from the cache by firing the remove event and cleaning all existing * references. * * @param existingType * Existing type. * @param events * {@link Events} */ private void removeDueToTypeChange(Type existingType, Events events) { existingType.removeReferences(); fireAndSave(new NodeEvent(existingType, NodeEventType.REMOVED, null), events); log.warn("Type " + existingType + " removed from the class-cache as it changed the base type."); }
/** * Merges given annotation when it exist in the structure as interface. * * @param given * {@link AnnotationType} * @param existing * {@link InterfaceType} * @param events * Events to process. */ private void mergeAnnotationAsInterface(AnnotationType given, InterfaceType existing, Events events) { for (ClassType classType : existing.getRealizingClasses()) { // this should update the references in the class type correctly classType.addInterface(given); } // must be specified as new, no other way fireAndSave(new NodeEvent(given, NodeEventType.NEW, NodeEventDetails.INITIALIZED), events); }
@Test(dataProvider = "types", expectedExceptions = { ClassCacheModificationException.class }) public void addNewUnInitializedTypeThatWasNotKnown(Class<? extends Type> type) throws Exception { String fqn = "class"; when(lookup.findByFQN(fqn)).thenReturn(null); service.lookup = lookup; Type theClass = construct(type, fqn); Events events = service.merge(theClass); Events expected = new Events(); expected.addEvent(new NodeEvent(theClass, NodeEventType.NEW, NodeEventDetails.NOT_INITIALIZED)); assertEvents(events, expected); }
@Test(dataProvider = "types") public void addNewInitializedTypeThatWasNotKnown(Class<? extends Type> type) throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; when(lookup.findByFQN(fqn)).thenReturn(null); service.lookup = lookup; Type theClass = construct(type, fqn, hash, modifiers); Events events = service.merge(theClass); Events expected = new Events(); expected.addEvent(new NodeEvent(theClass, NodeEventType.NEW, NodeEventDetails.INITIALIZED)); assertEvents(events, expected); }
@Test(dataProvider = "typesWithMethods") public void addNewMethodExceptionNotThere(Class<? extends Type> clazz) throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; TypeWithMethods given = (TypeWithMethods) construct(clazz, fqn, hash, modifiers); String exceptionName = "ex"; ClassType exception = new ClassType(exceptionName); String mName = "a"; String mReturnType = "mReturnType"; MethodType m = build(mName, 0, mReturnType, null, new HashSet<>(Arrays.asList(exception)), null); given.addMethod(m); when(lookup.findByFQN(fqn)).thenReturn(null); when(lookup.findByFQN(exceptionName)).thenReturn(null); service.lookup = lookup; Events events = service.merge(given); // methods with different parameters are different methods and should not be merged. assertThat(given.getMethods(), hasItem(m)); assertThat(given.getMethods().size(), is(1)); Events expected = new Events(); expected.addEvent(new NodeEvent(given, NodeEventType.NEW, NodeEventDetails.INITIALIZED)); expected.addEvent(new NodeEvent(exception, NodeEventType.NEW, NodeEventDetails.NOT_INITIALIZED)); assertEvents(events, expected); }
@Test(dataProvider = "typesWithMethods") public void mergeWithNotInitializedNewMethodExceptionNotThere(Class<? extends Type> clazz) throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; TypeWithMethods given = (TypeWithMethods) construct(clazz, fqn, hash, modifiers); TypeWithMethods stored = (TypeWithMethods) construct(clazz, fqn); String exceptionName = "ex"; ClassType exception = new ClassType(exceptionName); String mName = "a"; String mReturnType = "mReturnType"; MethodType m = build(mName, 0, mReturnType, null, new HashSet<>(Arrays.asList(exception)), null); given.addMethod(m); when(lookup.findByFQN(fqn)).thenReturn(stored); when(lookup.findByFQN(exceptionName)).thenReturn(null); service.lookup = lookup; Events events = service.merge(given); // methods with different parameters are different methods and should not be merged. assertThat(stored.getMethods(), hasItem(m)); assertThat(stored.getMethods().size(), is(1)); Events expected = new Events(); expected.addEvent(new NodeEvent(stored, NodeEventType.CHANGED, NodeEventDetails.INITIALIZED)); expected.addEvent(new NodeEvent(exception, NodeEventType.NEW, NodeEventDetails.NOT_INITIALIZED)); expected.addEvent(new NodeEvent(stored, NodeEventType.CHANGED, NodeEventDetails.METHOD_CHANGED_OR_ADDED)); assertEvents(events, expected); }
@Test(dataProvider = "typesWithMethods") public void addNewMethodAnnotationNotThere(Class<? extends Type> clazz) throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; TypeWithMethods c = (TypeWithMethods) construct(clazz, fqn, hash, modifiers); String mName = "mName"; String mReturnType = "mReturnType"; int mMod = 7; String aName = "aName"; AnnotationType a = new AnnotationType(aName); c.addMethod(build(mName, mMod, mReturnType, null, null, new HashSet<>(Arrays.asList(new AnnotationType[] { a })))); when(lookup.findByFQN(fqn)).thenReturn(null); when(lookup.findByFQN(aName)).thenReturn(null); service.lookup = lookup; Events events = service.merge(c); Events expected = new Events(); expected.addEvent(new NodeEvent(c, NodeEventType.NEW, NodeEventDetails.INITIALIZED)); expected.addEvent(new NodeEvent(a, NodeEventType.NEW, NodeEventDetails.NOT_INITIALIZED)); assertThat(c.getMethods().size(), is(1)); assertThat(c.getMethods(), hasItem(build(mName, mMod, mReturnType, null, null, new HashSet<>(Arrays.asList(new AnnotationType[] { a }))))); assertEvents(events, expected); }
@Test(dataProvider = "typesWithMethods") public void addNewMethodAnnotationThere(Class<? extends Type> clazz) throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; TypeWithMethods c = (TypeWithMethods) construct(clazz, fqn, hash, modifiers); String mName = "mName"; String mReturnType = "mReturnType"; int mMod = 7; String aName = "aName"; AnnotationType a = new AnnotationType(aName); c.addMethod(build(mName, mMod, mReturnType, null, null, new HashSet<>(Arrays.asList(new AnnotationType[] { a })))); when(lookup.findByFQN(fqn)).thenReturn(null); when(lookup.findByFQN(aName)).thenReturn(a); service.lookup = lookup; Events events = service.merge(c); Events expected = new Events(); expected.addEvent(new NodeEvent(c, NodeEventType.NEW, NodeEventDetails.INITIALIZED)); assertThat(c.getMethods().size(), is(1)); assertThat(c.getMethods(), hasItem(build(mName, mMod, mReturnType, null, null, new HashSet<>(Arrays.asList(new AnnotationType[] { a }))))); assertEvents(events, expected); }
@Test(dataProvider = "types") public void addNewAnnotationReferredTypeNotThere(Class<? extends Type> clazz) throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; TypeWithAnnotations c = construct(clazz, fqn, hash, modifiers); String annotationFQN = "fqnAnnotation"; AnnotationType annotation = new AnnotationType(annotationFQN); c.addAnnotation(annotation); // we assume that nothing is there yet when(lookup.findByFQN(fqn)).thenReturn((Type) null); when(lookup.findByFQN(annotationFQN)).thenReturn(null); service.lookup = lookup; Events events = service.merge((Type) c); // assert bidirectional assertThat(c.getAnnotations().size(), is(1)); assertThat(c.getAnnotations(), hasItem(annotation)); assertThat(annotation.getAnnotatedTypes(), hasItem(c)); Events expected = new Events(); expected.addEvent(new NodeEvent((Type) c, NodeEventType.NEW, NodeEventDetails.INITIALIZED)); expected.addEvent(new NodeEvent(annotation, NodeEventType.NEW, NodeEventDetails.NOT_INITIALIZED)); expected.addEvent(new ReferenceEvent((Type) c, annotation, ReferenceType.ANNOTATION)); assertEvents(events, expected); }
@Test(dataProvider = "typesWithMethods") public void addNewMethodExceptionThere(Class<? extends Type> clazz) throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; TypeWithMethods given = (TypeWithMethods) construct(clazz, fqn, hash, modifiers); String exceptionName = "ex"; ClassType exception = new ClassType(exceptionName); String mName = "a"; String mReturnType = "mReturnType"; MethodType m = build(mName, 0, mReturnType, null, new HashSet<>(Arrays.asList(exception)), null); given.addMethod(m); when(lookup.findByFQN(fqn)).thenReturn(null); when(lookup.findByFQN(exceptionName)).thenReturn(exception); service.lookup = lookup; Events events = service.merge(given); // methods with different parameters are different methods and should not be merged. assertThat(given.getMethods(), hasItem(m)); assertThat(given.getMethods().size(), is(1)); Events expected = new Events(); expected.addEvent(new NodeEvent(given, NodeEventType.NEW, NodeEventDetails.INITIALIZED)); assertEvents(events, expected); }
@Test(dataProvider = "types") public void addNewInitializedTypeThatIsKnownUninitialized(Class<? extends Type> type) throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; Type notInitialized = construct(type, fqn); when(lookup.findByFQN(fqn)).thenReturn(notInitialized); service.lookup = lookup; Type initialized = construct(type, fqn, hash, modifiers); Events events = service.merge(initialized); Events expected = new Events(); expected.addEvent(new NodeEvent(notInitialized, NodeEventType.CHANGED, NodeEventDetails.INITIALIZED)); assertEvents(events, expected); }
@Test(dataProvider = "typesWithMethods") public void mergeWithNotInitializedNewMethodReturnType(Class<? extends Type> clazz) throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; TypeWithMethods c = (TypeWithMethods) construct(clazz, fqn, hash, modifiers); String mName = "mName"; int mMod = 7; String returnType = "void"; List<String> params = Arrays.asList(new String[] { "java.util.List", "java.lang.String" }); c.addMethod(build(mName, mMod, returnType, params, null, null)); TypeWithMethods stored = (TypeWithMethods) construct(clazz, fqn); when(lookup.findByFQN(fqn)).thenReturn(stored); service.lookup = lookup; Events events = service.merge(c); Events expected = new Events(); expected.addEvent(new NodeEvent(c, NodeEventType.CHANGED, NodeEventDetails.INITIALIZED)); expected.addEvent(new NodeEvent(stored, NodeEventType.CHANGED, NodeEventDetails.METHOD_CHANGED_OR_ADDED)); String returnTypeExpected = "void"; assertThat(stored.getMethods().size(), is(1)); assertThat(stored.getMethods(), hasItem(build(mName, mMod, returnTypeExpected, params, null, null))); assertEvents(events, expected); }
@Test(dataProvider = "types") public void addNewInitializedTypeThatIsKnownInitializedWithDifferentHash(Class<? extends Type> type) throws Exception { String fqn = "class"; String hash = "hash"; String hashStored = "hashStored"; int modifiers = 0; Type storedClass = construct(type, fqn, hashStored, modifiers); when(lookup.findByFQN(fqn)).thenReturn(storedClass); service.lookup = lookup; Type initialized = construct(type, fqn, hash, modifiers); Events events = service.merge(initialized); Events expected = new Events(); expected.addEvent(new NodeEvent(storedClass, NodeEventType.CHANGED, NodeEventDetails.HASH_ADDED)); assertEvents(events, expected); }
@Test public void addNewSuperclassReferenceReferredTypeThere() throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; ClassType c = new ClassType(fqn, hash, modifiers); String fqnSuper = "fqnSuper"; ClassType s = new ClassType(fqnSuper); c.addSuperClass(s); when(lookup.findByFQN(fqn)).thenReturn(null); when(lookup.findByFQN(fqnSuper)).thenReturn(s); service.lookup = lookup; Events events = service.merge(c); Events expected = new Events(); expected.addEvent(new NodeEvent(c, NodeEventType.NEW, NodeEventDetails.INITIALIZED)); expected.addEvent(new ReferenceEvent(c, s, ReferenceType.SUPERCLASS)); // assert bidirectional assertThat(c.getSuperClasses().size(), is(1)); assertThat(c.getSuperClasses(), hasItem(s)); assertThat(s.getSubClasses(), hasItem(c)); assertEvents(events, expected); }
@Test public void addNewSuperInterfaceReferredTypeThere() throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; InterfaceType c = new InterfaceType(fqn, hash, modifiers); String fqnSuper = "fqnSuper"; InterfaceType s = new InterfaceType(fqnSuper); c.addSuperInterface(s); when(lookup.findByFQN(fqnSuper)).thenReturn(s); service.lookup = lookup; Events events = service.merge(c); Events expected = new Events(); expected.addEvent(new NodeEvent(c, NodeEventType.NEW, NodeEventDetails.INITIALIZED)); expected.addEvent(new ReferenceEvent(c, s, ReferenceType.SUPERINTERFACE)); // assert bidirectional assertThat(c.getSuperInterfaces().size(), is(1)); assertThat(c.getSuperInterfaces(), hasItem(s)); assertThat(s.getSubInterfaces(), hasItem(c)); assertEvents(events, expected); }
@Test public void addNewSuperInterfaceReferredTypeNotThere() throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; InterfaceType c = new InterfaceType(fqn, hash, modifiers); String fqnSuper = "fqnSuper"; InterfaceType s = new InterfaceType(fqnSuper); c.addSuperInterface(s); when(lookup.findByFQN(fqnSuper)).thenReturn(s); service.lookup = lookup; Events events = service.merge(c); Events expected = new Events(); expected.addEvent(new NodeEvent(c, NodeEventType.NEW, NodeEventDetails.INITIALIZED)); expected.addEvent(new ReferenceEvent(c, s, ReferenceType.SUPERINTERFACE)); // assert bidirectional assertThat(c.getSuperInterfaces().size(), is(1)); assertThat(c.getSuperInterfaces(), hasItem(s)); assertThat(s.getSubInterfaces(), hasItem(c)); assertEvents(events, expected); }
@Test public void mergeWithNotInitializedNewRealizedInterfaceReferredTypeThere() throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; ClassType c = new ClassType(fqn, hash, modifiers); // note that the interface can only be non-initialized String fqnSuper = "fqnSuper"; InterfaceType s = new InterfaceType(fqnSuper); c.addInterface(s); ClassType stored = new ClassType(fqn); // we assume that nothing is there yet when(lookup.findByFQN(fqn)).thenReturn(stored); when(lookup.findByFQN(fqnSuper)).thenReturn(s); service.lookup = lookup; Events events = service.merge(c); Events expected = new Events(); expected.addEvent(new NodeEvent(stored, NodeEventType.CHANGED, NodeEventDetails.INITIALIZED)); expected.addEvent(new ReferenceEvent(stored, s, ReferenceType.REALIZE_INTERFACE)); // assert bidirectional assertThat(stored.getRealizedInterfaces().size(), is(1)); assertThat(stored.getRealizedInterfaces(), hasItem(s)); assertThat(s.getRealizingClasses(), hasItem(stored)); assertEvents(events, expected); }
@Test(dataProvider = "typesWithMethods") public void mergeWithNotInitializedNewMethodModifier(Class<? extends Type> clazz) throws Exception { String fqn = "class"; String hash = "hash"; int modifiers = 0; TypeWithMethods c = (TypeWithMethods) construct(clazz, fqn, hash, modifiers); String mName = "mName"; int mMod = Modifiers.getModifiers(Modifier.PUBLIC | Modifier.STATIC); c.addMethod(build(mName, mMod, null, null, null, null)); TypeWithMethods stored = (TypeWithMethods) construct(clazz, fqn); when(lookup.findByFQN(fqn)).thenReturn(stored); service.lookup = lookup; Events events = service.merge(c); Events expected = new Events(); expected.addEvent(new NodeEvent(c, NodeEventType.CHANGED, NodeEventDetails.INITIALIZED)); expected.addEvent(new NodeEvent(stored, NodeEventType.CHANGED, NodeEventDetails.METHOD_CHANGED_OR_ADDED)); assertThat(stored.getMethods().size(), is(1)); assertThat(stored.getMethods(), hasItem(build(mName, Modifiers.getModifiers(Modifier.PUBLIC + Modifier.STATIC), null, null, null, null))); assertEvents(events, expected); }
@Test(dataProvider = "types") public void mergeModifiers(Class<? extends Type> type) throws Exception { String fqn = "fqn"; int m = Modifiers.getModifiers(Modifier.PUBLIC); String hash = "hash"; Type given = construct(type, fqn, hash, m); assertThat(Modifiers.isPublic(given.getModifiers()), is(true)); String hashStored = "stored"; int modStored = Modifiers.getModifiers(Modifier.PRIVATE); Type stored = construct(type, fqn, hashStored, modStored); assertThat(Modifiers.isPrivate(stored.getModifiers()), is(true)); when(lookup.findByFQN(fqn)).thenReturn(stored); service.lookup = lookup; Events events = service.merge(given); // so now we expect that the stored on is both public and private assertThat(Modifiers.isPublic(stored.getModifiers()), is(true)); assertThat(Modifiers.isPrivate(stored.getModifiers()), is(true)); Events expected = new Events(); expected.addEvent(new NodeEvent(stored, NodeEventType.CHANGED, NodeEventDetails.HASH_ADDED)); expected.addEvent(new NodeEvent(stored, NodeEventType.CHANGED, NodeEventDetails.MODIFIERS_CHANGED)); assertEvents(events, expected); }
@Test public void handleTwoLevelInstanceAreNotSupported() throws Exception { // that is a class, that has a superclass, that has a superclass String[] fqns = new String[] { "1", "2", "3" }; int[] modifiers = new int[] { 0, 1, 2 }; String[] hashes = new String[] { "a", "b", "c" }; ClassType base = new ClassType(fqns[0], hashes[0], modifiers[0]); ClassType firstSuper = new ClassType(fqns[1], hashes[1], modifiers[1]); ClassType secondSuper = new ClassType(fqns[2], hashes[2], modifiers[2]); base.addSuperClass(firstSuper); firstSuper.addSuperClass(secondSuper); // we assume that nothing is there yet when(lookup.findByFQN(fqns[0])).thenReturn(null); when(lookup.findByFQN(fqns[1])).thenReturn(null); when(lookup.findByFQN(fqns[2])).thenReturn(null); service.lookup = lookup; Events events = service.merge(base); // We do not support multi-level structures! Events expected = new Events(); expected.addEvent(new NodeEvent(base, NodeEventType.NEW, NodeEventDetails.INITIALIZED)); expected.addEvent(new NodeEvent(firstSuper, NodeEventType.NEW, NodeEventDetails.NOT_INITIALIZED)); expected.addEvent(new ReferenceEvent(base, firstSuper, ReferenceType.SUPERCLASS)); assertEvents(events, expected); }