/*
* Copyright 2011 Henry Coles
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package org.pitest.classinfo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.Serializable;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.pitest.classpath.ClassloaderByteArraySource;
import org.pitest.coverage.codeassist.ClassUtils;
import org.pitest.functional.Option;
import org.pitest.util.IsolationUtils;
public class RepositoryTest {
private Repository testee;
@Mock
private ClassByteArraySource source;
@Mock
private HashFunction hashFunction;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
this.testee = new Repository(new ClassloaderByteArraySource(
IsolationUtils.getContextClassLoader()), this.hashFunction);
}
@Test
public void shouldReturnTrueWhenAskedForKnownClass() {
assertTrue(this.testee.hasClass(new ClassName(Integer.class)));
}
@Test
public void shouldReturnFalseWhenAskedForUnknownClass() {
assertFalse(this.testee.hasClass(new ClassName("never.heard.of.you")));
}
@Test
public void shouldOnlyCheckSourceForUnknownClassesOnce() {
this.testee = new Repository(this.source);
when(this.source.getBytes(anyString())).thenReturn(Option.<byte[]> none());
this.testee.hasClass(new ClassName("foo"));
this.testee.hasClass(new ClassName("foo"));
verify(this.source, times(1)).getBytes("foo");
}
@Test
public void shouldReturnNoneWhenAskedForUnknownClass() {
assertEquals(Option.none(),
this.testee.fetchClass(ClassName.fromString("never.heard.of.you")));
}
@Test
public void shouldOnlyLookForUnknownClassesOnce() {
this.testee = new Repository(this.source);
when(this.source.getBytes(anyString())).thenReturn(Option.<byte[]> none());
this.testee.fetchClass(ClassName.fromString("foo"));
this.testee.fetchClass(ClassName.fromString("foo"));
verify(this.source, times(1)).getBytes("foo");
}
@Test
public void shouldOnlyQuerySourceForAnUnknownClassOnce() {
this.testee = new Repository(this.source);
when(this.source.getBytes(anyString())).thenReturn(Option.<byte[]> none());
this.testee.hasClass(new ClassName("foo"));
this.testee.fetchClass(ClassName.fromString("foo"));
verify(this.source, times(1)).getBytes("foo");
}
@Test
public void shouldReturnInfoForClassOnClassPath() {
assertTrue(this.testee.fetchClass(Integer.class).hasSome());
}
@Test
public void shouldOnlyLookForKnownClassOnce() throws ClassNotFoundException {
this.testee = new Repository(this.source);
when(this.source.getBytes(anyString())).thenReturn(
Option.some(ClassUtils.classAsBytes(String.class)));
this.testee.fetchClass(ClassName.fromString("foo"));
this.testee.fetchClass(ClassName.fromString("foo"));
verify(this.source, times(1)).getBytes("foo");
}
@Test
public void shouldDetectInterfacesAsInterfaces() {
final Option<ClassInfo> anInterface = this.testee
.fetchClass(Serializable.class);
assertTrue(anInterface.value().isInterface());
}
@Test
public void shouldDetectInterfacesAsAbstract() {
final Option<ClassInfo> anInterface = this.testee
.fetchClass(Serializable.class);
assertTrue(anInterface.value().isAbstract());
}
@Test
public void shouldDetectConcreteClassesAsNotInterfaces() {
final Option<ClassInfo> aClass = this.testee.fetchClass(String.class);
assertFalse(aClass.value().isInterface());
}
@Test
public void shouldDetectConcreteClassesAsNotAbstract() {
final Option<ClassInfo> aClass = this.testee.fetchClass(String.class);
assertFalse(aClass.value().isAbstract());
}
public static class SimpleInnerClass {
}
@Test
public void shouldReportOuterClassForStaticInnerClasses() {
final String actual = getOuterClassNameFor(SimpleInnerClass.class);
assertEquals(RepositoryTest.class.getName().replace(".", "/"), actual);
}
@Test
public void shouldReportOuterClassForLocalClasses() {
final Object local = new Object() {
};
final String actual = getOuterClassNameFor(local.getClass());
assertEquals(RepositoryTest.class.getName().replace(".", "/"), actual);
}
public class NonStaticInnerClass {
}
@Test
public void shouldReportOuterClassForNonStaticInnerClasses() {
final String actual = getOuterClassNameFor(NonStaticInnerClass.class);
assertEquals(RepositoryTest.class.getName().replace(".", "/"), actual);
}
public static class OuterStaticInnerClass {
public static class InnerStaticClass {
}
}
@Test
public void shouldReportInnermstOuterClassForNestedInnerClasses() {
final String actual = getOuterClassNameFor(OuterStaticInnerClass.InnerStaticClass.class);
assertEquals(
RepositoryTest.OuterStaticInnerClass.class.getName().replace(".", "/"),
actual);
}
static class Foo {
}
static class Bar extends Foo {
}
@Test
public void shouldReportSuperClass() {
final Option<ClassInfo> aClass = this.testee.fetchClass(Bar.class);
assertEquals(new ClassName(Foo.class), aClass.value().getSuperClass()
.value().getName());
}
@Test
public void shouldReportSuperClassAsObjectWhenNoneDeclared() {
final Option<ClassInfo> aClass = this.testee.fetchClass(Foo.class);
assertEquals(new ClassName(Object.class), aClass.value().getSuperClass()
.value().getName());
}
@Test
public void shouldReportNoSuperClassForObject() {
final Option<ClassInfo> aClass = this.testee.fetchClass(Object.class);
assertEquals(Option.none(), aClass.value().getSuperClass());
}
@Test
public void shouldReportCodeLines() {
final Option<ClassInfo> aClass = this.testee
.fetchClass(RepositoryTest.class);
aClass.value().isCodeLine(139); // flakey
}
@Ignore
static class Annotated {
}
@Test
public void shouldRecordClassLevelAnnotations() {
final Option<ClassInfo> aClass = this.testee.fetchClass(Annotated.class);
assertTrue(aClass.value().hasAnnotation(Ignore.class));
}
static class HasAnnotatedMethod {
@Test
public void foo() {
}
}
@Test
public void shouldRecordMethodLevelAnnotations() {
final Option<ClassInfo> aClass = this.testee
.fetchClass(HasAnnotatedMethod.class);
assertTrue(aClass.value().hasAnnotation(Test.class));
}
static interface ITop {
}
static class Top implements ITop {
}
static class Middle extends Top {
}
static class Bottom extends Middle {
}
@Test
public void shouldCorrectlyNegotiateClassHierachies() {
final Option<ClassInfo> aClass = this.testee.fetchClass(Bottom.class);
assertTrue(aClass.value().descendsFrom(Middle.class));
assertTrue(aClass.value().descendsFrom(Top.class));
assertTrue(aClass.value().descendsFrom(Object.class));
assertFalse(aClass.value().descendsFrom(String.class));
}
@Test
public void doesNotTreatInterfacesAsPartOfClassHierachy() {
final Option<ClassInfo> aClass = this.testee.fetchClass(Bottom.class);
assertFalse(aClass.value().descendsFrom(ITop.class));
}
@Test
public void shouldRecordSourceFile() {
final Option<ClassInfo> aClass = this.testee.fetchClass(String.class);
assertEquals("String.java", aClass.value().getSourceFileName());
}
@Test
public void shouldCalculateHashForSuppledClass() {
this.testee.fetchClass(String.class);
verify(this.hashFunction).hash(any(byte[].class));
}
private String getOuterClassNameFor(final Class<?> clazz) {
return this.testee.fetchClass(clazz).value().getOuterClass().value()
.getName().asInternalName();
}
}