package org.eclipse.tracecompass.statesystem.core.tests;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import java.util.Iterator;
+
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
import org.eclipse.tracecompass.statesystem.core.backend.StateHistoryBackendFactory;
import org.eclipse.tracecompass.statesystem.core.exceptions.AttributeNotFoundException;
import org.eclipse.tracecompass.statesystem.core.exceptions.StateValueTypeException;
+import org.eclipse.tracecompass.statesystem.core.exceptions.TimeRangeException;
import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
import org.eclipse.tracecompass.statesystem.core.statevalue.ITmfStateValue;
import org.eclipse.tracecompass.statesystem.core.statevalue.TmfStateValue;
import org.junit.Before;
import org.junit.Test;
+import com.google.common.collect.Iterators;
+
/**
* Test the {@link StateSystemUtils} class
*
}
+ /**
+ * Test that iterator returns the correct intervals:
+ * <ul>
+ * <li>intervals for the correct quark</li>
+ * <li>ordered intervals</li>
+ * <li>intervals covering the correct time range</li>
+ * </ul>
+ */
+ @Test
+ public void testIteratorOverQuark() {
+ ITmfStateSystem ss = fStateSystem;
+ assertNotNull(ss);
+
+ for (int quark = 0; quark < ss.getNbAttributes(); quark++) {
+ Iterator<ITmfStateInterval> iterator = StateSystemUtils.getIteratorOverQuark(ss, quark, Long.MIN_VALUE, Long.MAX_VALUE);
+ ITmfStateInterval prevInterval = null;
+ ITmfStateInterval currInterval = null;
+
+ while (iterator.hasNext()) {
+ currInterval = iterator.next();
+
+ assertEquals(quark, currInterval.getAttribute());
+ if (prevInterval == null) {
+ /* This is the first interval for this attribute */
+ assertEquals(currInterval.getStartTime(), ss.getStartTime());
+ } else {
+ assertEquals(prevInterval.getEndTime() + 1, currInterval.getStartTime());
+ }
+
+ prevInterval = currInterval;
+ }
+
+ assertNotNull("Iterator should have returned at least one interval", currInterval);
+ assertEquals(ss.getCurrentEndTime(), currInterval.getEndTime());
+ }
+ }
+
+ /**
+ * Test that the correct exception is thrown by getIteratorOverQuark when
+ * the lower bound argument is strictly greater than the upper bound
+ * argument
+ */
+ @Test(expected = TimeRangeException.class)
+ public void testIteratorOverQuarkTimeRangeException() {
+ ITmfStateSystem ss = fStateSystem;
+ assertNotNull(ss);
+ StateSystemUtils.getIteratorOverQuark(ss, 0, ss.getCurrentEndTime(), ss.getStartTime());
+ }
+
+ /**
+ * Test that getIteratorOverQuark returns the correct intervals for a range
+ * included in the state system range
+ */
+ @Test
+ public void testIteratorOverQuarkSubrange() {
+ ITmfStateSystem ss = fStateSystem;
+ assertNotNull(ss);
+
+ int quark;
+ try {
+ quark = ss.getQuarkAbsolute(DUMMY_STRING);
+
+ Iterator<ITmfStateInterval> iterator = StateSystemUtils.getIteratorOverQuark(ss, quark, 1200L, 1400L);
+
+ /* There should be a first interval ranging from 1200L to 1499L */
+ assertTrue(iterator.hasNext());
+ ITmfStateInterval interval = iterator.next();
+ assertNotNull(interval);
+ assertEquals(1200L, interval.getStartTime());
+ assertEquals(1499, interval.getEndTime());
+
+ /* There should not be a next interval */
+ assertFalse(iterator.hasNext());
+ } catch (AttributeNotFoundException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ /**
+ * With the query end > ss.end, query some intervals, then add a few
+ * intervals to the ss such that end now becomes < ss.end and make sure
+ * those new intervals are picked up
+ */
+ @Test
+ public void testIteratorOverQuarkAddMoreIntervals() {
+ try {
+ IStateHistoryBackend backend = StateHistoryBackendFactory.createInMemoryBackend(DUMMY_STRING, START_TIME);
+ ITmfStateSystemBuilder ss = StateSystemFactory.newStateSystem(backend);
+ int quark = ss.getQuarkAbsoluteAndAdd(DUMMY_STRING);
+
+ ss.modifyAttribute(1200L, TmfStateValue.newValueInt(10), quark);
+ ss.modifyAttribute(1500L, TmfStateValue.newValueInt(20), quark);
+
+ /* We should have 2 intervals if we iterate at this point */
+ Iterator<ITmfStateInterval> iterator = StateSystemUtils.getIteratorOverQuark(ss, quark, 0, 1700L);
+ assertEquals(2, Iterators.size(iterator));
+
+ /* Reset the iterator */
+ iterator = StateSystemUtils.getIteratorOverQuark(ss, quark, 0, 1700L);
+
+ /* Add an interval, updating the ss.end time */
+ ss.closeHistory(2000L);
+
+ /* We should have 3 intervals if we iterate at this point */
+ assertEquals(3, Iterators.size(iterator));
+ } catch (StateValueTypeException e) {
+ fail(e.getMessage());
+ }
+ }
}
package org.eclipse.tracecompass.statesystem.core;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
+import java.util.NoSuchElementException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
return null;
}
+ /**
+ * Iterator over the intervals of a given attribute. Not thread-safe.
+ *
+ * @param ss
+ * The state system on which to query intervals
+ *
+ * @param quark
+ * The key to the attribute to iterate over
+ * @param start
+ * The begin of the range of intervals to iterate over, if start
+ * is before the state system's start time, the iteration will
+ * begin at the state system's start time.
+ * @param end
+ * The end of the range of intervals to iterate over, it can be
+ * greater than the current state system's end time, iteration
+ * will end at the smallest of the two.
+ * @return an Iterator over the intervals of a given attribute, with
+ * intervals ordered
+ * @throws TimeRangeException
+ * If end < start.
+ * @since 2.1
+ */
+ public static Iterator<ITmfStateInterval> getIteratorOverQuark(ITmfStateSystem ss, int quark, long start, long end) {
+ if (end < start) {
+ throw new TimeRangeException("iterateOverQuark: end < start !"); //$NON-NLS-1$
+ }
+
+ return new Iterator<ITmfStateInterval>() {
+ private @Nullable ITmfStateInterval fCurrent;
+
+ private long getNextQueryTime() {
+ if (fCurrent != null) {
+ return fCurrent.getEndTime() + 1;
+ }
+ /* Iteration has not started yet */
+ return Long.max(start, ss.getStartTime());
+ }
+
+ @Override
+ public boolean hasNext() {
+ /*
+ * Compute the query's real end time here, to update it if the
+ * iterator is used during state system build
+ */
+ long realEnd = Long.min(end, ss.getCurrentEndTime());
+
+ /*
+ * Ensure that the next query time falls within state system and
+ * query time range. By definition getNextQueryTime() is larger
+ * than the state system's start time.
+ */
+ return getNextQueryTime() <= realEnd;
+ }
+
+ @Override
+ public ITmfStateInterval next() {
+ if (hasNext()) {
+ try {
+ return fCurrent = ss.querySingleState(getNextQueryTime(), quark);
+ } catch (StateSystemDisposedException e) {
+ /* GOTO throw NoSuchElementException. */
+ }
+ }
+ throw new NoSuchElementException();
+ }
+ };
+ }
+
}