3535import static org .junit .Assert .assertNotNull ;
3636import static org .junit .Assert .assertTrue ;
3737
38+ import java .lang .reflect .InvocationTargetException ;
39+ import java .util .ArrayList ;
40+ import java .util .Collection ;
3841import java .util .LinkedList ;
42+ import java .util .concurrent .ExecutionException ;
3943
4044import org .junit .After ;
4145import org .junit .Before ;
4246import org .junit .Test ;
4347import org .scijava .Context ;
4448import org .scijava .Priority ;
49+ import org .scijava .console .OutputEvent .Source ;
4550import org .scijava .plugin .Plugin ;
51+ import org .scijava .thread .ThreadService ;
4652
4753/**
4854 * Tests {@link ConsoleService}.
@@ -70,6 +76,129 @@ public void testProcessArgs() {
7076 assertTrue (consoleService .getInstance (FooArgument .class ).argsHandled );
7177 }
7278
79+ /**
80+ * Tests the {@link OutputListener}-related API:
81+ * <ul>
82+ * <li>{@link ConsoleService#addOutputListener(OutputListener)}</li>
83+ * <li>{@link ConsoleService#removeOutputListener(OutputListener)}</li>
84+ * <li>{@link ConsoleService#notifyListeners(OutputEvent)}</li>
85+ * </ul>
86+ */
87+ @ Test
88+ public void testOutputListeners () throws InterruptedException ,
89+ ExecutionException
90+ {
91+ final ThreadService threadService =
92+ consoleService .context ().service (ThreadService .class );
93+
94+ final String stdoutBefore = "hoc" ;
95+ final String stderrBefore = "us-" ;
96+ final String stdoutGlobal = "poc" ;
97+ final String stderrGlobal = "us-" ;
98+ final String stdoutLocal = "abra" ;
99+ final String stderrLocal = "-cad" ;
100+ final String stdoutAfter = "ave" ;
101+ final String stderrAfter = "rs-" ;
102+
103+ final ArrayList <OutputEvent > events = new ArrayList <OutputEvent >();
104+ final OutputListener outputListener = new OutputTracker (events );
105+
106+ final Runnable r = new Printer (stdoutLocal , stderrLocal );
107+
108+ // This output should _not_ be announced!
109+ System .out .print (stdoutBefore );
110+ System .err .print (stderrBefore );
111+
112+ consoleService .addOutputListener (outputListener );
113+
114+ // This output _should_ be announced!
115+ System .out .print (stdoutGlobal );
116+ System .err .print (stderrGlobal );
117+ threadService .run (r ).get ();
118+
119+ consoleService .removeOutputListener (outputListener );
120+
121+ // This output should _not_ be announced!
122+ threadService .run (r ).get ();
123+ System .out .print (stdoutAfter );
124+ System .err .print (stderrAfter );
125+
126+ assertEquals (4 , events .size ());
127+
128+ assertOutputEvent (Source .STDOUT , stdoutGlobal , false , events .get (0 ));
129+ assertOutputEvent (Source .STDERR , stderrGlobal , false , events .get (1 ));
130+ assertOutputEvent (Source .STDOUT , stdoutLocal , true , events .get (2 ));
131+ assertOutputEvent (Source .STDERR , stderrLocal , true , events .get (3 ));
132+ }
133+
134+ /** Tests multiple simultaneous {@link Context}s listening for output. */
135+ @ Test
136+ public void testMultipleContextOutput () throws InterruptedException ,
137+ ExecutionException
138+ {
139+ final Context c1 = consoleService .context ();
140+ final Context c2 = new Context ();
141+
142+ final ConsoleService cs1 = consoleService ;
143+ final ConsoleService cs2 = c2 .service (ConsoleService .class );
144+
145+ final ThreadService ts1 = c1 .service (ThreadService .class );
146+ final ThreadService ts2 = c2 .service (ThreadService .class );
147+
148+ final ArrayList <OutputEvent > events1 = new ArrayList <OutputEvent >();
149+ cs1 .addOutputListener (new OutputTracker (events1 ));
150+ final ArrayList <OutputEvent > events2 = new ArrayList <OutputEvent >();
151+ cs2 .addOutputListener (new OutputTracker (events2 ));
152+
153+ final String globalOut = "and" ;
154+ final String globalErr = "-zo" ;
155+ final String c1RunOut = "mbi" ;
156+ final String c1RunErr = "es-" ;
157+ final String c2RunOut = "sha" ;
158+ final String c2RunErr = "zam" ;
159+ final String c1InvokeOut = "-cl" ;
160+ final String c1InvokeErr = "eop" ;
161+ final String c2InvokeOut = "atr" ;
162+ final String c2InvokeErr = "a" ;
163+
164+ System .out .print (globalOut );
165+ System .err .print (globalErr );
166+
167+ ts1 .run (new Printer (c1RunOut , c1RunErr )).get ();
168+ ts2 .run (new Printer (c2RunOut , c2RunErr )).get ();
169+
170+ ts1 .run (new EDTPrinter (ts1 , c1InvokeOut , c1InvokeErr ));
171+ ts2 .run (new EDTPrinter (ts2 , c2InvokeOut , c2InvokeErr ));
172+
173+ c2 .dispose ();
174+
175+ assertEquals (6 , events1 .size ());
176+ assertOutputEvent (Source .STDOUT , globalOut , false , events1 .get (0 ));
177+ assertOutputEvent (Source .STDERR , globalErr , false , events1 .get (1 ));
178+ assertOutputEvent (Source .STDOUT , c1RunOut , true , events1 .get (2 ));
179+ assertOutputEvent (Source .STDERR , c1RunErr , true , events1 .get (3 ));
180+ assertOutputEvent (Source .STDOUT , c1InvokeOut , true , events1 .get (4 ));
181+ assertOutputEvent (Source .STDERR , c1InvokeErr , true , events1 .get (5 ));
182+
183+ assertEquals (6 , events2 .size ());
184+ assertOutputEvent (Source .STDOUT , globalOut , false , events2 .get (0 ));
185+ assertOutputEvent (Source .STDERR , globalErr , false , events2 .get (1 ));
186+ assertOutputEvent (Source .STDOUT , c2RunOut , true , events2 .get (2 ));
187+ assertOutputEvent (Source .STDERR , c2RunErr , true , events2 .get (3 ));
188+ assertOutputEvent (Source .STDOUT , c2InvokeOut , true , events2 .get (4 ));
189+ assertOutputEvent (Source .STDERR , c2InvokeErr , true , events2 .get (5 ));
190+ }
191+
192+ // -- Helper methods --
193+
194+ private void assertOutputEvent (final Source source , final String output ,
195+ final boolean contextual , final OutputEvent event )
196+ {
197+ assertEquals (source , event .getSource ());
198+ assertEquals (output , event .getOutput ());
199+ assertEquals (contextual , event .isContextual ());
200+ }
201+
73202 // -- Helper classes --
74203
75204 @ Plugin (type = ConsoleArgument .class , priority = Priority .HIGH_PRIORITY )
@@ -89,4 +218,64 @@ public void handle(final LinkedList<String> args) {
89218
90219 }
91220
221+ private static class OutputTracker implements OutputListener {
222+
223+ private final Collection <OutputEvent > events ;
224+
225+ private OutputTracker (final Collection <OutputEvent > events ) {
226+ this .events = events ;
227+ }
228+
229+ @ Override
230+ public void outputOccurred (final OutputEvent event ) {
231+ events .add (event );
232+ }
233+
234+ }
235+
236+ private static class Printer implements Runnable {
237+
238+ private final String out ;
239+ private final String err ;
240+
241+ private Printer (final String out , final String err ) {
242+ this .out = out ;
243+ this .err = err ;
244+ }
245+
246+ @ Override
247+ public void run () {
248+ System .out .print (out );
249+ System .err .print (err );
250+ }
251+
252+ }
253+
254+ private static class EDTPrinter implements Runnable {
255+
256+ private final ThreadService ts ;
257+ private final Printer p ;
258+
259+ private EDTPrinter (final ThreadService ts , final String out ,
260+ final String err )
261+ {
262+ this .ts = ts ;
263+ p = new Printer (out , err );
264+ }
265+
266+ @ Override
267+ public void run () {
268+ try {
269+ ts .invoke (p );
270+ }
271+ catch (final InvocationTargetException exc ) {
272+ throw new RuntimeException (exc );
273+ }
274+ catch (final InterruptedException exc ) {
275+ throw new RuntimeException (exc );
276+ }
277+ }
278+
279+ }
280+
92281}
0 commit comments