package uk.nhs.kch.rassyeyanie.common.testing.unit;
import java.io.IOException;
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import uk.nhs.kch.rassyeyanie.framework.HL7AdditionalConstants;
import uk.nhs.kch.rassyeyanie.framework.Util;
import ca.uhn.hl7v2.HL7Exception;
import ca.uhn.hl7v2.model.AbstractMessage;
import ca.uhn.hl7v2.parser.EncodingNotSupportedException;
import ca.uhn.hl7v2.parser.PipeParser;
/*
* Message contexts:
* Input message -- a read only SPoT
* for translations to refer to while processing messages
* Expected message -- a read only SPoT for
* expected messages in comparisons
* Output message -- this is a mutable object that eventually becomes
* the 'actual' in asserts
*
*/
public class TestContext<T extends AbstractMessage>
{
private final String inputSource;
private final String outputSource;
private final String expectedSource;
private final Processor[] processors;
private Class<? extends AbstractMessage> messageType;
private T outputMessage;
private String inputText;
private String outputText;
private String expectedText;
private String originalInputText;
private T inputMessage;
private T expectedMessage;
private PipeParser pipeParser;
// exposed for instances where tests want to manually call translations
private Exchange exchange;
public TestContext(String inputSource,
String expectedSource,
Class<T> messageType,
T outputMessage,
Processor... processors)
{
this.inputSource = inputSource;
this.outputSource = null;
this.expectedSource = expectedSource;
this.processors = processors;
this.messageType = messageType;
this.outputMessage = outputMessage;
}
public TestContext(String inputSource,
String expectedSource,
T outputMessage,
Processor... processors)
{
this.inputSource = inputSource;
this.outputSource = null;
this.expectedSource = expectedSource;
this.processors = processors;
this.outputMessage = outputMessage;
}
@SuppressWarnings("rawtypes")
public static TestContextFactory getFactory()
{
return new TestContextFactory();
}
private static String getClassResourceStream(Class<?> streamClass,
String string)
throws IOException
{
return IOUtils
.toString(streamClass.getClassLoader().getResourceAsStream(string))
.replace('\n', '\r')
.replace("\r\r", "\r");
}
public void prepare()
throws IOException, EncodingNotSupportedException, HL7Exception
{
this.pipeParser = Util.createVersionedParser("2.4");
this.loadResources();
this.parseMessages();
this.prepareExchange();
this.originalInputText = this.inputText;
this.inputText = this.inputMessage.encode();
}
private void loadResources()
throws IOException
{
this.inputText = this.loadResource(this.inputSource);
if (this.outputSource != null)
{
this.setOutputText(this.loadResource(this.outputSource));
}
this.expectedText = this.loadResource(this.expectedSource);
}
private String loadResource(String resourceFile)
throws IOException
{
return getClassResourceStream(this.getClass(), resourceFile);
}
@SuppressWarnings("unchecked")
private void parseMessages()
throws HL7Exception, EncodingNotSupportedException
{
this.inputMessage = (T) this.pipeParser.parse(this.inputText);
// if we haven't been given an output container -- use intermediate
// message
if (this.outputMessage == null)
{
// for backwards compatibility -- this allows old translations
// to be tested with new framework while we transition
this.outputMessage =
(T) this.pipeParser.parse(this.getOutputText() == null
? this.inputText
: this.getOutputText());
}
if (this.messageType == null)
{
this.messageType = this.outputMessage.getClass();
}
this.expectedMessage = (T) this.pipeParser.parse(this.expectedText);
}
private void prepareExchange()
{
this.setExchange(new TestExchange());
this.getExchange().getIn().setBody(this.outputMessage);
this
.getExchange()
.getIn()
.setHeader(
HL7AdditionalConstants.HL7_SOURCE_MESSAGE,
this.inputMessage);
}
public void runTest()
throws Exception
{
for (Processor processor : this.processors)
{
processor.process(this.getExchange());
}
}
@Override
public String toString()
{
int processorLength = this.processors.length;
String[] processorSimpleNames = new String[processorLength];
for (int i = 0; i < processorLength; i++)
processorSimpleNames[i] =
this.processors[i].getClass().getSimpleName();
String processorChain = StringUtils.join(processorSimpleNames, " -> ");
return processorChain + " (" + this.messageType.getSimpleName() + ")";
}
public String getInputSource()
{
return this.inputSource;
}
public String getInputText()
{
return this.inputText;
}
public String getExpectedText()
{
return this.expectedText;
}
public T getInputMessage()
{
return this.inputMessage;
}
public T getExpectedMessage()
{
return this.expectedMessage;
}
// Alias to aide writing test code
public T getActualResult()
{
return this.getOutputMessage();
}
public AbstractMessage getAbstractExpectedMessage()
{
return this.getExpectedMessage();
}
public AbstractMessage getAbstactActualResult()
{
return this.getOutputMessage();
}
public T getOutputMessage()
{
return this.outputMessage;
}
public void setOutputMessage(T outputMessage)
{
this.outputMessage = outputMessage;
}
public WrappedMessage getExpectedMessageQueryable()
{
return new WrappedMessage(this.getExpectedMessage());
}
public WrappedMessage getActualResultQueryable()
{
return new WrappedMessage(this.getActualResult());
}
public Exchange getExchange()
{
return this.exchange;
}
public void setExchange(Exchange exchange)
{
this.exchange = exchange;
}
public String getOutputText()
{
return this.outputText;
}
public void setOutputText(String outputText)
{
this.outputText = outputText;
}
public String getOriginalInputText()
{
return this.originalInputText;
}
public void setOriginalInputText(String originalInputText)
{
this.originalInputText = originalInputText;
}
}