net.sf.expectit.ExpectImpl Maven / Gradle / Ivy
package net.sf.expectit;
/*
* #%L
* ExpectIt
* %%
* Copyright (C) 2014 Alexey Gavrilov and contributors
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import static net.sf.expectit.ExpectBuilder.validateDuration;
import static net.sf.expectit.Utils.toDebugString;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.sf.expectit.interact.InteractBuilder;
import net.sf.expectit.matcher.Matcher;
/**
* An implementation of the Expect interface which delegates actual work to SingleInputExpect
* objects.
*/
class ExpectImpl extends AbstractExpectImpl {
private static final Logger LOG = Logger.getLogger(ExpectImpl.class.getName());
static final int INFINITE_TIMEOUT = -1; // value representing infinite timeout
private final OutputStream output;
private final SingleInputExpect[] inputs;
private final Charset charset;
private final Appendable echoOutput;
@Deprecated
private final boolean errorOnTimeout;
private final ExecutorService executor;
private final String lineSeparator;
private final boolean exceptionOnFailure;
private final boolean autoFlushEcho;
ExpectImpl(
final long timeout,
final OutputStream output,
final SingleInputExpect[] inputs,
final Charset charset,
final Appendable echoOutput,
final boolean errorOnTimeoutOld,
final String lineSeparator,
final boolean exceptionOnFailure,
final boolean autoFlushEcho) {
super(timeout);
this.output = output;
this.inputs = inputs;
this.charset = charset;
this.echoOutput = echoOutput;
this.errorOnTimeout = errorOnTimeoutOld;
this.exceptionOnFailure = exceptionOnFailure;
this.lineSeparator = lineSeparator;
this.autoFlushEcho = autoFlushEcho;
executor = Executors.newFixedThreadPool(
inputs.length,
new NamedExecutorThreadFactory("expect-"));
}
void start() {
for (SingleInputExpect input : inputs) {
input.start(executor);
}
}
@Override
public R expectIn(int input, long timeoutMs, Matcher matcher)
throws IOException {
if (LOG.isLoggable(Level.FINE)) {
LOG.fine(
String.format(
"Expect matcher '%s' with timeout %d (ms) in input #%d",
toDebugString(matcher),
timeoutMs,
input));
}
R result = inputs[input].expect(timeoutMs, matcher);
if (exceptionOnFailure && !result.isSuccessful()) {
final String inputBuffer = inputs[input].getBuffer().toString();
throw new ExpectIOException(
"Expect operation fails (timeout: "
+ timeoutMs + " ms) for matcher: " + matcher, inputBuffer);
}
if (errorOnTimeout && !result.isSuccessful()) {
throw new AssertionError(
"Expect timeout (" + timeoutMs + " ms) for matcher: " + matcher);
}
return result;
}
@Override
public Expect withTimeout(long duration, TimeUnit unit) {
validateDuration(duration);
return new ExpectTimeoutAdapter(this, unit.toMillis(duration));
}
@Override
public Expect withInfiniteTimeout() {
return new ExpectTimeoutAdapter(this, -1);
}
@Override
public Expect send(String string) throws IOException {
byte[] bytes = string.getBytes(charset);
writeBytes(bytes);
echoString(string);
return this;
}
@Override
public Expect sendLine() throws IOException {
return sendLine("");
}
@Override
public Expect sendLine(String string) throws IOException {
return send(string + lineSeparator);
}
@Override
public Expect sendBytes(byte[] bytes) throws IOException {
writeBytes(bytes);
echoString(new String(bytes, charset));
return this;
}
private void writeBytes(byte[] bytes) throws IOException {
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("Writing bytes: " + toDebugString(bytes, bytes.length, charset));
}
output.write(bytes);
output.flush();
}
private void echoString(String string) throws IOException {
if (echoOutput != null) {
echoOutput.append(string);
if (autoFlushEcho) {
Utils.flushAppendable(echoOutput);
}
}
}
@Override
public void close() throws IOException {
for (SingleInputExpect input : inputs) {
input.stop();
}
executor.shutdown();
if (autoFlushEcho) {
Utils.flushAppendable(echoOutput);
}
}
@Override
public InteractBuilder interact() {
return interactWith(0);
}
@Override
public InteractBuilder interactWith(final int input) {
return interactWithInternal(this, input);
}
InteractBuilder interactWithInternal(final AbstractExpectImpl expect, final int input) {
if (input >= inputs.length || input < 0) {
throw new IllegalArgumentException("Input index is out of bounds: " + input);
}
return new InteractBuilderImpl(expect, input);
}
@Override
SingleInputExpect[] getInputs() { return inputs; }
}