blob: e2b42f7998415c65da209f843e09b47b9a113828 [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2015 Christian W. Damus and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Christian W. Damus - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.papyrus.uml.profile.tests;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.window.Window;
import org.eclipse.papyrus.junit.utils.JUnitUtils;
import org.eclipse.papyrus.uml.profile.service.ui.RefreshProfileDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Shell;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
/**
* A JUnit rule that interacts (or not) with the editor's Profile Migration Dialog.
*/
public class DialogInteractionRule extends TestWatcher {
private DialogInteractionKind interactionMode;
private volatile boolean active;
private final Lock lock = new ReentrantLock();
private final Condition dialogInteractionDone = lock.newCondition();
private final AtomicReference<Boolean> interactionResult = new AtomicReference<>();
public void assertInteraction() {
waitForInteraction();
Boolean result = interactionResult.get();
assertThat("No dialog interaction occurred", result, notNullValue());
assertThat("Expected dialog interaction did not occur: " + interactionMode, result, is(true));
}
@Override
protected void starting(Description description) {
interactionMode = JUnitUtils.getAnnotation(description, DialogInteractionMode.class).value();
active = true;
Display.getDefault().asyncExec(new InteractionRunnable());
}
@Override
protected void finished(Description description) {
active = false;
}
protected void waitForInteraction() {
Display current = Display.getCurrent();
if (current != null) {
// This is the UI thread. Flush it
for (;;) {
try {
if (!current.readAndDispatch()) {
break;
}
} catch (Exception e) {
// It may provide diagnostic information for the test
e.printStackTrace();
}
}
} else {
// Synchronize with the UI thread
Display.getDefault().syncExec(new Runnable() {
@Override
public void run() {
// Pass
}
});
}
}
static <W extends Window> W findWindow(Class<W> windowType) {
W result = null;
for (Shell next : Display.getDefault().getShells()) {
if (windowType.isInstance(next.getData())) {
result = windowType.cast(next.getData());
break;
}
}
return result;
}
static Button findButton(Composite composite, int code) {
Button result = null;
Integer id = code;
Control[] controls = composite.getChildren();
for (int i = 0; (i < controls.length) && (result == null); i++) {
final Control next = controls[i];
if (next instanceof Button) {
Button button = (Button) next;
if (id.equals(button.getData())) {
result = button;
}
} else if (next instanceof Composite) {
result = findButton((Composite) next, code);
}
}
return result;
}
//
// Nested types
//
/**
* An asynchronous UI runnable that is schedule to run after the editor has opened,
* and so after it has shown the profile migration dialog (if any), to interact with
* it if it is open.
*/
private class InteractionRunnable implements Runnable {
@Override
public void run() {
Boolean result = false;
if (active) {
RefreshProfileDialog dialog = findWindow(RefreshProfileDialog.class);
switch (interactionMode) {
case CANCEL:
if (dialog != null) {
result = true;
findButton(dialog.getShell(), IDialogConstants.CANCEL_ID).notifyListeners(SWT.Selection, new Event());
}
break;
case OK:
if (dialog != null) {
result = true;
findButton(dialog.getShell(), IDialogConstants.OK_ID).notifyListeners(SWT.Selection, new Event());
}
break;
default: // NONE
result = dialog == null;
break;
}
}
lock.lock();
try {
interactionResult.set(result);
dialogInteractionDone.signalAll();
} finally {
lock.unlock();
}
}
}
}