/** Testet das Auswählen, Anhören und Löschen eines Klingeltons. */
  @Test
  public final void testSoundSelection() {
    controller.setDialogStage(mockedDialogStage);

    // Alarm vorgeben
    final Alarm alarm =
        new Alarm(DateTimeUtil.getLocalDateTimeForString("01.01.1970 00:00:00"), "Bla");
    controller.setAlarm(alarm);
    FXTestUtils.awaitEvents();

    // Sound setzen
    controller.setRingtone("Sound");
    FXTestUtils.awaitEvents();

    assertFalse(alarmNoSoundButton.isDisabled());
    assertFalse(alarmPlaySoundButton.isDisabled());

    // Sound-Abspielen-Schaltfläche betätigen
    final AudioPlayer player = mock(AudioPlayer.class);
    controller.getGuiHelper().setAudioPlayer(player);
    click(alarmPlaySoundButton);
    waitForThreads();
    verify(player)
        .playInThread(
            isA(ThreadHelper.class), eq("Sound"), isA(Thread.UncaughtExceptionHandler.class));

    // Sound-Löschen-Schaltfläche betätigen
    click(alarmNoSoundButton);
    waitForThreads();

    // sicherstellen, dass nicht Dialog geschlossen worden wäre
    verify(mockedDialogStage, never()).close();

    assertEquals("kein Klingelton gewählt", alarmSelectSoundButton.getText());
  }
  /** Testet Anzeige der Fehlermeldung bei leerem Datum. */
  @Test
  public final void testErrorDateEmpty() {
    controller.setDialogStage(mockedDialogStage);

    controller.setExistingAlarms(Arrays.asList(new Alarm()));

    // Alarm vorgeben
    controller.setAlarm(new Alarm());
    FXTestUtils.awaitEvents();

    // Datum leeren
    Platform.runLater(
        new Runnable() {
          public void run() {
            alarmDatePicker.setValue(null);
          }
        });
    FXTestUtils.awaitEvents();

    final MessageHelper messageHelper = mock(MessageHelper.class);
    controller.getGuiHelper().setMessageHelper(messageHelper);

    // Speichern-Schaltfläche betätigen
    click(alarmSaveButton);
    waitForThreads();

    // sicherstellen, dass nicht Dialog geschlossen worden wäre
    verify(mockedDialogStage, never()).close();

    // sicherstellen, dass Fehlermeldung erscheint
    verify(messageHelper)
        .showDialogMessage(
            anyString(), eq("Ein Datum muss angegeben werden.\n"), isA(ResourceBundle.class));
  }
  /** Testet das Verwerfen der Änderungen. */
  @Test
  public final void testCancel() {
    controller.setDialogStage(mockedDialogStage);

    // Alarm vorgeben
    final LocalDateTime now = LocalDateTime.now();
    final Alarm alarm = new Alarm(now, "bla");
    controller.setAlarm(alarm);
    FXTestUtils.awaitEvents();

    // deaktivieren
    click(alarmEnabledCheckbox);
    waitForThreads();

    Platform.runLater(
        new Runnable() {
          public void run() {
            // Datum setzen
            alarmDatePicker.setValue(DateTimeUtil.getLocalDateForString("24.12.2014"));

            // Zeit setzen
            alarmTimePicker.setValue(DateTimeUtil.getLocalTimeForString("12:00:00"));

            // Beschreibung setzen
            alarmDescriptionTextField.setText("Test");
          }
        });
    FXTestUtils.awaitEvents();

    // Sound setzen
    controller.setRingtone("Sound");
    FXTestUtils.awaitEvents();

    // Abbrechen-Schaltfläche betätigen
    final Button alarmCancelButton = (Button) scene.lookup("#alarmCancelButton");
    click(alarmCancelButton);
    waitForThreads();

    // sicherstellen, dass Dialog geschlossen worden wäre
    verify(mockedDialogStage, timeout(WAIT_FOR_EVENT)).close();

    // sicherstellen, dass Alarm ursprüngliche Werte hat
    assertTrue(alarm.isEnabled());
    assertEquals(now, alarm.getDateTime());
    assertEquals("bla", alarm.getDescription());
    assertEquals(null, alarm.getSound());
  }
  /** Testet das Speichern der Änderungen. */
  @Test
  public final void testApplyChanges() {
    controller.setDialogStage(mockedDialogStage);

    // Alarm vorgeben
    final Alarm alarm =
        new Alarm(DateTimeUtil.getLocalDateTimeForString("01.01.1970 00:00:00"), "Bla");
    controller.setAlarm(alarm);
    FXTestUtils.awaitEvents();

    // deaktivieren
    click(alarmEnabledCheckbox);
    waitForThreads();

    Platform.runLater(
        new Runnable() {
          public void run() {
            // Datum setzen
            alarmDatePicker.setValue(DateTimeUtil.getLocalDateForString("24.12.2014"));

            // Zeit setzen
            alarmTimePicker.setValue(DateTimeUtil.getLocalTimeForString("12:00:00"));

            // Beschreibung setzen
            alarmDescriptionTextField.setText("Test");
          }
        });
    FXTestUtils.awaitEvents();

    // Sound setzen
    controller.setRingtone("Sound");
    FXTestUtils.awaitEvents();

    // Speichern-Schaltfläche betätigen
    click(alarmSaveButton);
    waitForThreads();

    // sicherstellen, dass Dialog geschlossen worden wäre
    verify(mockedDialogStage, timeout(WAIT_FOR_EVENT)).close();

    // sicherstellen, dass Alarm neue Werte hat
    assertFalse(alarm.isEnabled());
    assertEquals(
        DateTimeUtil.getLocalDateTimeForString("24.12.2014 12:00:00"), alarm.getDateTime());
    assertEquals("Test", alarm.getDescription());
    assertEquals("Sound", alarm.getSound());
  }
  /** Testet den Zustand der Steuerelemente nach Öffnen des Dialogs. */
  @Test
  public final void testInitialState() {
    final TextField hoursTextField = (TextField) scene.lookup("#hoursTextField");

    // Alarm vorgeben
    controller.setAlarm(
        new Alarm(DateTimeUtil.getLocalDateTimeForString("24.12.2014 12:00:00"), "Test"));
    FXTestUtils.awaitEvents();

    // sicherstellen, dass Formularfelder korrekt gefüllt sind
    assertTrue(alarmEnabledCheckbox.isSelected());
    assertEquals(DateTimeUtil.getLocalDateForString("24.12.2014"), alarmDatePicker.getValue());
    assertEquals(DateTimeUtil.getLocalTimeForString("12:00:00"), alarmTimePicker.getValue());
    assertEquals("12", hoursTextField.getText());
    assertEquals("Test", alarmDescriptionTextField.getText());

    assertEquals("kein Klingelton gewählt", alarmSelectSoundButton.getText());
    assertTrue(alarmNoSoundButton.isDisabled());
    assertTrue(alarmPlaySoundButton.isDisabled());
  }
  /** Testet Anzeige bzw. Ausbleiben von Fehlermeldungen beim Speichern eines Alarms. */
  @Test
  public final void testErrorWhenSavingAlarm() {
    final List<DataErrors> testCases = new Vector<>();

    // Anlegen/Bearbeiten eines Alarms mit Zeitstempel in Vergangenheit
    testCases.add(
        new DataErrors(
            1,
            "Der Alarm-Zeitpunkt muss in der Zukunft liegen.\n",
            null,
            new Alarm(DateTimeUtil.getLocalDateTimeForString("01.01.1970 00:00:00"), "Alarm")));
    // Anlegen/Bearbeiten eines Alarms mit Zeitstempel in Zukunft
    testCases.add(
        new DataErrors(
            0,
            null,
            null,
            new Alarm(DateTimeUtil.getLocalDateTimeForString("01.01.2050 00:00:00"), "Alarm")));
    // Anlegen/Bearbeiten eines inaktiven Alarms mit Zeitstempel in Vergangenheit
    testCases.add(
        new DataErrors(
            0,
            null,
            null,
            new Alarm(
                DateTimeUtil.getLocalDateTimeForString("01.01.1970 00:00:00"),
                "Alarm",
                null,
                false)));
    // Anlegen/Bearbeiten eines inaktiven Alarms mit Zeitstempel in Zukunft
    testCases.add(
        new DataErrors(
            0,
            null,
            null,
            new Alarm(
                DateTimeUtil.getLocalDateTimeForString("01.01.2050 00:00:00"),
                "Alarm",
                null,
                false)));

    // Anlegen eines Alarms mit identischem Zeitstempel
    testCases.add(
        new DataErrors(
            1,
            "Ein anderer Alarm mit demselben Zeitpunkt existiert bereits.\n",
            Arrays.asList(
                new Alarm(DateTimeUtil.getLocalDateTimeForString("01.01.2050 00:00:00"), "Alarm1")),
            new Alarm(DateTimeUtil.getLocalDateTimeForString("01.01.2050 00:00:00"), "Alarm2")));
    // Anlegen eines Alarms mit unterschiedlichem Zeitstempel
    testCases.add(
        new DataErrors(
            0,
            null,
            Arrays.asList(
                new Alarm(DateTimeUtil.getLocalDateTimeForString("01.01.2050 00:00:00"), "Alarm1")),
            new Alarm(DateTimeUtil.getLocalDateTimeForString("11.11.2160 00:00:00"), "Alarm2")));
    // Bearbeiten eines Alarms ohne Änderung des Zeitstempels
    final Alarm alarm =
        new Alarm(
            DateTimeUtil.getLocalDateTimeForString("01.01.2050 00:00:00"),
            "Alarm1"); // genau ein Objekt
    testCases.add(new DataErrors(0, null, Arrays.asList(alarm), alarm));

    for (final DataErrors testCase : testCases) {
      reset(mockedDialogStage);
      controller.setDialogStage(mockedDialogStage);

      controller.setExistingAlarms(testCase.existingAlarms);
      controller.setAlarm(testCase.alarm);
      FXTestUtils.awaitEvents();

      final MessageHelper messageHelper = mock(MessageHelper.class);
      controller.getGuiHelper().setMessageHelper(messageHelper);

      // Speichern-Schaltfläche betätigen
      click(alarmSaveButton);
      waitForThreads();

      // sicherstellen, dass nicht Dialog geschlossen worden wäre
      verify(mockedDialogStage, testCase.numberOfCalls > 0 ? never() : times(1)).close();

      // sicherstellen, dass Fehlermeldung erscheint bzw. nicht
      verify(messageHelper, times(testCase.numberOfCalls))
          .showDialogMessage(
              anyString(),
              testCase.errorMessage == null ? anyString() : eq(testCase.errorMessage),
              isA(ResourceBundle.class));
    }
  }