@Before
  public void setup() {
    measurements = new ArrayList<Measurement>();
    for (int i = 0; i < 4; i++) {
      measurements.add(new Measurement(i, i, i, new Date(0, 0, 0, 0, 1, 2 * i)));
    }

    sensor = mock(Sensor.class);
    when(sensor.getSensorName()).thenReturn("LHC");

    presenter.sensorManager = mock(SensorManager.class);
    when(presenter.sensorManager.getVisibleSensor()).thenReturn(sensor);
    presenter.onEvent(new ViewStreamEvent(sensor));

    stream = mock(MeasurementStream.class);
    when(stream.getMeasurements()).thenReturn(measurements);

    presenter.sessionManager = mockSessionManager();
    when(presenter.sessionManager.getMeasurementStream("LHC")).thenReturn(stream);
    when(presenter.sessionManager.isSessionStarted()).thenReturn(true);

    listener = mock(MeasurementPresenter.Listener.class);
    presenter.registerListener(listener);

    presenter.settingsHelper = mock(SettingsHelper.class);
    when(presenter.settingsHelper.getAveragingTime()).thenReturn(1);
    EVENT = new SessionChangeEvent(new Session());
  }
  @Test
  public void shouldNotCluster() {
    state.recording().startRecording();
    presenter.setZoom(4000);

    assertThat(presenter.getTimelineView()).contains(measurements.get(3), measurements.get(2));
  }
 @Test
 public void shouldAllowToZoomOutAfterMoreDataArrives() {
   state.recording().startRecording();
   presenter.setZoom(8000);
   presenter.getTimelineView();
   triggerMeasurement(measurement1);
   assertThat(presenter.canZoomOut()).isTrue();
 }
  @Test
  public void shouldShowLastNMillis() {
    state.recording().startRecording();
    presenter.setZoom(100);

    List<Measurement> result = presenter.getTimelineView();

    assertThat(result).contains(measurements.get(3));
    assertThat(result).excludes(measurements.get(2));
  }
  @Test
  public void shouldUpdateTheFullView() {
    state.recording().startRecording();
    presenter.getFullView();
    presenter.sessionManager = mockSessionManager();

    triggerMeasurement(measurement1);
    List<Measurement> result = presenter.getFullView();

    assertThat(result).contains(measurement1);
  }
  @Test
  public void shouldNotUpdateWhenViewingASession() {
    presenter.getFullView();
    presenter.sessionManager = mockSessionManager();
    when(presenter.sessionManager.isSessionStarted()).thenReturn(false);
    when(presenter.sessionManager.isSessionSaved()).thenReturn(true);

    presenter.onEvent(EVENT);
    triggerMeasurement(measurement1);

    assertThat(presenter.getFullView()).isEmpty();
  }
  @Test
  public void shouldAppendWithoutRecalculating() {
    state.recording().startRecording();
    presenter.setZoom(4000);
    presenter.getTimelineView();
    presenter.sessionManager = mockSessionManager();

    triggerMeasurement(measurement1);
    List<Measurement> result = presenter.getTimelineView();

    assertThat(result).contains(measurement1, measurements.get(3)).excludes(measurements.get(2));
  }
  //
  //  @Test
  //  public void shouldScrollLeft()
  //  {
  //    presenter.setZoom(4000);
  //
  //    presenter.scroll(-0.5);
  //
  //    assertThat(presenter.getTimelineView(), hasItem(equalTo(measurements.get(2))));
  //    assertThat(presenter.getTimelineView(), hasItem(equalTo(measurements.get(1))));
  //  }
  //
  //  @Test
  //  public void shouldScrollRight()
  //  {
  //    presenter.setZoom(4000);
  //
  //    presenter.scroll(-1);
  //    presenter.scroll(0.5);
  //
  //    assertThat(presenter.getTimelineView(), hasItem(equalTo(measurements.get(2))));
  //    assertThat(presenter.getTimelineView(), hasItem(equalTo(measurements.get(1))));
  //  }
  //
  //  @Test
  //  public void shouldNotScrollTooMuchRight()
  //  {
  //    presenter.setZoom(4000);
  //
  //    presenter.scroll(2);
  //
  //    assertThat(presenter.getTimelineView(), hasItem(equalTo(measurements.get(3))));
  //    assertThat(presenter.getTimelineView(), hasItem(equalTo(measurements.get(2))));
  //  }
  //
  //  @Test
  //  public void shouldNotScrollTooMuchLeft()
  //  {
  //    presenter.setZoom(4000);
  //
  //    presenter.scroll(-10);
  //
  //    assertThat(presenter.getTimelineView(), hasItem(equalTo(measurements.get(1))));
  //    assertThat(presenter.getTimelineView(), hasItem(equalTo(measurements.get(0))));
  //  }
  //
  //  @Test
  //  public void shouldNotifyListenersOnScroll()
  //  {
  //    presenter.scroll(-10);
  //
  //    verify(listener).onViewUpdated();
  //  }
  //
  //  @Test
  //  public void shouldNotUpdateTheTimelineIfScrolled()
  //  {
  //    presenter.setZoom(4000);
  //    presenter.scroll(-0.5);
  //
  //    presenter.getTimelineView();
  //    triggerMeasurement(measurement1);
  //
  //    assertThat(presenter.getTimelineView(), not(hasItem(equalTo(measurement1))));
  //  }
  //
  //  @Test
  //  public void shouldAverage()
  //  {
  //    when(presenter.settingsHelper.getAveragingTime()).thenReturn(4);
  //    Measurement expected = new Measurement(1.5, 1.5, 1.5, new Date(0, 0, 0, 0, 1, 3));
  //
  //    presenter.onEvent(EVENT);
  //
  //    assertThat(presenter.getFullView(), hasItem(equalTo(expected)));
  //  }
  //
  @Test
  public void shouldAverageOnTheFly() {
    state.recording().startRecording();
    when(presenter.settingsHelper.getAveragingTime()).thenReturn(4);
    Measurement expected = new Measurement(3.5, 3.5, 3.5, new Date(0, 0, 0, 0, 1, 5));

    presenter.onEvent(EVENT);
    triggerMeasurement(measurement1);
    triggerMeasurement(measurement2);

    assertThat(presenter.getFullView()).contains(expected, measurement2);
  }
  @Test
  public void shouldOnlyUpdateFromVisibleSensorEvents() {
    presenter.getFullView();
    presenter.sessionManager = mockSessionManager();
    when(presenter.sessionManager.isSessionStarted()).thenReturn(false);
    when(presenter.sessionManager.isSessionSaved()).thenReturn(true);

    presenter.onEvent(EVENT);
    triggerMeasurement(measurement1);

    assertThat(presenter.getFullView()).isEmpty();
  }
  @Test
  public void timelineViewShouldBeEmptyWithoutASession() {
    when(presenter.sessionManager.isSessionSaved()).thenReturn(false);
    when(presenter.sessionManager.isSessionStarted()).thenReturn(false);

    assertThat(presenter.getTimelineView()).isEmpty();
  }
  @Test
  public void shouldUnregisterListeners() {
    presenter.unregisterListener(listener);

    triggerMeasurement(measurement1);

    verifyZeroInteractions(listener);
  }
  @Test
  public void fullViewShouldBeEmptyWithoutASession() {
    when(presenter.sessionManager.isSessionSaved()).thenReturn(false);
    when(presenter.sessionManager.isSessionStarted()).thenReturn(false);

    triggerMeasurement(measurement1);

    assertThat(presenter.getFullView()).isEmpty();
  }
  @Test
  public void shouldNotifyListenersAboutNewAveragedMeasurements() {
    state.recording().startRecording();
    when(presenter.settingsHelper.getAveragingTime()).thenReturn(4);
    Measurement expected = new Measurement(3.5, 3.5, 3.5, new Date(0, 0, 0, 0, 1, 5));
    presenter.registerListener(listener);

    triggerMeasurement(measurement1);
    triggerMeasurement(measurement2);
    triggerMeasurement(new Measurement(0, 0, 0, new Date(0, 0, 0, 0, 1, 10)));

    verify(listener, atLeastOnce()).onAveragedMeasurement(expected);
  }
 private void triggerMeasurement(Measurement measurement) {
   presenter.onEvent(new MeasurementEvent(measurement, sensor));
 }
  @Test
  public void shouldHandleEmptyList() {
    when(stream.getMeasurements()).thenReturn(new ArrayList<Measurement>());

    assertThat(presenter.getTimelineView()).isEmpty();
  }
 @Test
 public void shouldNotAllowToZoomOutTooMuch() {
   presenter.setZoom(100000000);
   assertThat(presenter.canZoomOut()).isFalse();
 }
 @Test
 public void shouldAllowToZoomOut() {
   state.recording().startRecording();
   presenter.setZoom(2000);
   assertThat(presenter.canZoomOut()).isTrue();
 }