package hudson.plugins.cigame.model;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import hudson.model.Job;
import hudson.model.Run;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class ScoreHistoryEntryTest {
private ScoreHistoryEntry entry = new ScoreHistoryEntry();
@Mock
@SuppressWarnings("rawtypes")
TestRun mockRun1;
@Mock
@SuppressWarnings("rawtypes")
TestRun mockRun2;
@Before
public void setUp() throws Exception {
when(mockRun1.getExternalizableId()).thenReturn("MockRun#1");
when(mockRun1.getNumber()).thenReturn(1);
when(mockRun1.compareTo(Mockito.any(TestRun.class))).thenCallRealMethod();
when(mockRun2.getExternalizableId()).thenReturn("MockRun#2");
when(mockRun2.getNumber()).thenReturn(2);
when(mockRun2.compareTo(Mockito.any(TestRun.class))).thenCallRealMethod();
fillEntry();
}
private void fillEntry() throws IOException {
this.entry.setAwardedScore(3.0);
this.entry.setAwardingRuns(ImmutableList.of((Run<?,?>)mockRun1, (Run<?,?>)mockRun2));
}
@Test
public void theAwardedScoreStringShouldBePrefixedByPlusSignForPositiveScores() throws Exception {
entry.setAwardedScore(3.0);
assertEquals('+', entry.getAwardedScoreString().charAt(0));
}
@Test
public void nullRunsAreNotRemembered() throws Exception {
final Set<Run<?, ?>> originalRuns = this.entry.getAwardingRuns();
final List<Run<?, ?>> newRuns = Lists.newArrayList(originalRuns);
newRuns.add(0, null);
newRuns.add(null);
newRuns.add(2, null);
entry.setAwardingRuns(newRuns);
assertThat(entry.getAwardingRuns().size(), equalTo(originalRuns.size()));
for (Run<?, ?> run : entry.getAwardingRuns()) {
assertThat(run, is(notNullValue()));
}
}
@Test
public void theAwardedScoreStringShouldBePrefixedByMinusSignForNegativeScores() throws Exception {
entry.setAwardedScore(-0.5);
assertEquals('-', entry.getAwardedScoreString().charAt(0));
}
@Test
public void theAwardedRunsContains() throws Exception {
Set<TestRun> expected = ImmutableSet.of(mockRun2, mockRun1);
assertEquals(expected, entry.getAwardingRuns());
}
@Test
public void theAwardedRunsShouldBeSortedFromNewestToOldest() throws Exception {
Set<TestRun> expected = ImmutableSet.of(mockRun2, mockRun1);
Iterator<TestRun> expectedIter = expected.iterator();
Iterator<Run<?, ?>> actualIter = entry.getAwardingRuns().iterator();
while(expectedIter.hasNext() && actualIter.hasNext()) {
assertEquals(expectedIter.next(), actualIter.next());
}
assertFalse(expectedIter.hasNext());
assertFalse(actualIter.hasNext());
}
/*
* Strictly speaking, this is not really a unit-test because it does involve XStream directly.
* Since it runs very fast, we use it here anyway.
*/
@Test
public void itCanMarshal() throws Exception {
final String marshaled = marshal();
assertNotNull(marshaled);
assertTrue(marshaled.length() > 0);
}
/*
* Strictly speaking, this is not really a unit-test because it does involve XStream directly.
* Since it runs very fast, we use it here anyway.
*/
@Test
public void aMarshalledScoreEntryHasAllInfoInIt() throws Exception {
final String marshalled = marshal();
assertTrue("score is not contained", marshalled.contains(Double.toString(this.entry.getAwardedScore())));
assertTrue("run1 is not contained", marshalled.contains(mockRun1.getExternalizableId()));
assertTrue("run2 is not contained", marshalled.contains(mockRun2.getExternalizableId()));
}
/*
* Strictly speaking, this is not really a unit-test because it does involve XStream directly.
* Since it runs very fast, we use it here anyway.
*/
@Test
public void itCanUnmarshal() throws Exception {
final String marshaled = marshal();
ScoreHistoryEntry unmarshaled = umarshal(marshaled);
assertNotNull(unmarshaled);
}
/*
* Strictly speaking, this is not really a unit-test because it does involve XStream directly.
* Since it runs very fast, we use it here anyway.
*/
@Test
public void itCorrectlyMarshalsAndUnmarshalsAnEntry() throws Exception {
ScoreHistoryEntry unmarshaled = umarshal(marshal());
assertEquals(this.entry, unmarshaled);
}
private ScoreHistoryEntry umarshal(String marshaled) {
XStream xStream = createXStream(new TestRunCreationStrategy());
return (ScoreHistoryEntry) xStream.fromXML(marshaled);
}
private String marshal() {
XStream xStream = createXStream(null);
String xml = xStream.toXML(this.entry);
return xml;
}
private XStream createXStream(ScoreHistoryEntry.RunCreationStrategy strategy) {
XStream xStream = new XStream(new DomDriver());
xStream.setClassLoader(getClass().getClassLoader());
ScoreHistoryEntry.ConverterImpl converter;
if(strategy != null){
converter = new ScoreHistoryEntry.ConverterImpl(strategy);
} else{
converter = new ScoreHistoryEntry.ConverterImpl();
}
xStream.registerConverter(converter);
return xStream;
}
private class TestRunCreationStrategy implements ScoreHistoryEntry.RunCreationStrategy {
public Run<?, ?> createRunFromExternalId(String externalId) {
if(externalId.equals(mockRun1.getExternalizableId())) {
return mockRun1;
}
if(externalId.equals(mockRun2.getExternalizableId())) {
return mockRun2;
}
throw new IllegalStateException("Unknown run resolution: " + externalId);
}
}
public static abstract class TestRun<JobT extends Job<JobT,RunT>,RunT extends Run<JobT,RunT>> extends Run<JobT,RunT> {
protected TestRun(JobT job) throws IOException {
super(job);
}
@Override
public int compareTo(RunT that) {
//we implement a simple version of compareTo to make sure that the ScoreHistoryEntry can differ between two instances
return Integer.valueOf(getNumber()).compareTo(that.getNumber());
}
}
}