gt: 		Writer writer = new StringWriter();
context: package org.bladerunnerjs.api.spec.utility;
  
  import static org.hamcrest.MatcherAssert.assertThat;
  import static org.hamcrest.Matchers.containsString;
  import static org.hamcrest.Matchers.not;
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.fail;
  
  import java.io.File;
  import java.io.IOException;
  import java.io.OutputStream;
  import java.io.Reader;
  import java.io.StringWriter;
  import java.io.Writer;
  import java.net.ConnectException;
  import java.net.SocketTimeoutException;
  import java.nio.charset.Charset;
  
  import org.apache.commons.io.IOUtils;
  import org.apache.http.Header;
  import org.apache.http.HttpResponse;
  import org.apache.http.client.ClientProtocolException;
  import org.apache.http.client.methods.HttpGet;
  import org.apache.http.client.params.ClientPNames;
  import org.apache.http.conn.ConnectTimeoutException;
  import org.apache.http.entity.ContentType;
  import org.apache.http.impl.client.CloseableHttpClient;
  import org.apache.http.impl.client.DefaultHttpClient;
  import org.apache.http.params.CoreConnectionPNames;
  import org.apache.http.params.HttpParams;
  import org.apache.http.util.EntityUtils;
  import org.bladerunnerjs.api.BRJS;
  import org.bladerunnerjs.api.model.exception.ConfigException;
  import org.bladerunnerjs.utility.UnicodeReader;
  
  import com.google.common.base.Predicate;
  
  @SuppressWarnings("deprecation")
  public class WebappTester 
  {
  	
  	private static final int MAX_POLL_REQUESTS = 100;
  	private static final int POLL_INTERVAL = 500;
  	
  	private int defaultSocketTimeout = 9999999;
  	private int defaultConnectionTimeout = 9999999;
  	
  	private File filePathBase;
  	private int statusCode;
  	private String statusText;
  	
  	private HttpResponse httpResponse;
  	private String response;
  	private String contentType;
  	private String characterEncoding;
  	private String url;
  	
  	public String requestLocale = "";
  	private String defaultFileCharacterEncoding;
  	private int contentLength;
  	
  	public WebappTester(BRJS brjs, File filePathBase, int defaultSocketTimeout, int defaultConnectionTimeout)
  	{
  		this(filePathBase);
  		
  		try {
  			this.defaultSocketTimeout = defaultSocketTimeout;
  			this.defaultSocketTimeout = defaultConnectionTimeout;
  			defaultFileCharacterEncoding = brjs.bladerunnerConf().getDefaultFileCharacterEncoding();
  		}
  		catch(ConfigException e) {
  			throw new RuntimeException(e);
  		}
  	}
  	
  	public WebappTester(File filePathBase)
  	{
  		this.filePathBase = filePathBase;
  	}
  	
  	public WebappTester whenRequestMadeTo(String url, boolean followRedirects) throws ClientProtocolException, IOException
  	{
  		return whenRequestMadeTo(url, defaultSocketTimeout, defaultConnectionTimeout, followRedirects, null);
  	}
  	
  	public WebappTester whenRequestMadeTo(String url) throws ClientProtocolException, IOException
  	{
  		return whenRequestMadeTo(url, defaultSocketTimeout, defaultConnectionTimeout, true, null);
  	}
  	
  	public WebappTester whenRequestMadeTo(String url, OutputStream outputStream) throws ClientProtocolException, IOException
  	{
  		return whenRequestMadeTo(url, defaultSocketTimeout, defaultConnectionTimeout, true, outputStream);
  	}
  	
  	public WebappTester whenRequestMadeTo(String url, int socketTimeout, int connectionTimeout, boolean followRedirects, OutputStream outputStream) throws ClientProtocolException, IOException {
  		this.url = url;
  		CloseableHttpClient httpClient = new DefaultHttpClient();
  		httpClient.getParams().setIntParameter(CoreConnectionPNames.SO_TIMEOUT, socketTimeout);
  		httpClient.getParams().setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, connectionTimeout);	
  		
  		HttpGet get = new HttpGet(url);
  		HttpParams params = get.getParams();
  		params.setParameter(ClientPNames.HANDLE_REDIRECTS, followRedirects);
  		get.setParams(params);
  		get.addHeader("Accept-Language", requestLocale);
  		
  		httpResponse = httpClient.execute( get );
  		statusCode = httpResponse.getStatusLine().getStatusCode();
  		statusText = httpResponse.getStatusLine().getReasonPhrase();
  		if (outputStream != null) {
  			IOUtils.copy(httpResponse.getEntity().getContent(), outputStream);			
  		} else {
  			response = EntityUtils.toString(httpResponse.getEntity()); 
  		}
  		contentType = ContentType.getOrDefault(httpResponse.getEntity()).getMimeType();
  		
  		Header[] headers = httpResponse.getAllHeaders();
  		for(Header h:headers){
  			if (h.getName().equals("Content-Length")) {
  				contentLength = Integer.parseInt( h.getValue() );
  			}
  		}
  		
  		Charset charset = ContentType.getOrDefault(httpResponse.getEntity()).getCharset();
  		characterEncoding = (charset == null) ? "" : charset.displayName();
  		EntityUtils.consume(httpResponse.getEntity());
  		httpClient.getConnectionManager().shutdown();
  		httpClient.close();
  		return this;
  	}
  	
  	public WebappTester requestTimesOut(String url) throws IOException
  	{
  		try {
  			whenRequestMadeTo(url, 150, 150, false, null);
  			fail("Expected request to " + url + " to timeout, but came back with status code " + statusCode);
  		}
  		catch (SocketTimeoutException | ConnectTimeoutException | ConnectException ex)
  		{
  		}
  		
  		return this;		
  	}
  	
  	public String pollServerForStatusCode(String url, int requiredStatusCode) throws ClientProtocolException, IOException, InterruptedException
  	{
  		int requestCount = 0;
  		while(requestCount < MAX_POLL_REQUESTS)
  		{
  			try {
  				whenRequestMadeTo(url);
  			} catch (Exception ex) {
  				// do nothing
  			}
  			if (statusCode == requiredStatusCode)
  			{
  				return response;
  			}
  			requestCount++;
  			Thread.sleep(POLL_INTERVAL);
  		}
  		assertEquals("Never got required status code", requiredStatusCode, statusCode);
  		return null;
  	}
  	
  	public void pollServerUntilMatchesPredicate(String url, Predicate<String> predicate) throws ClientProtocolException, IOException, InterruptedException
  	{
  		int requestCount = 0;
  		
  		while(requestCount < MAX_POLL_REQUESTS)
  		{
  			try {
  				whenRequestMadeTo(url);
  			} catch (Exception ex) {
  				// do nothing
  			}
  			if (response != null && predicate.apply(response))
  			{
  				return;
  			}
  			requestCount++;
  			Thread.sleep(POLL_INTERVAL);
  		}
  		fail("Never got response that matched the predicate");
  	}
  	
  	public WebappTester printOutcome() 
  	{
  		System.out.println("URL:		"+url);
  		System.out.println("StatusCode:	"+statusCode);
  		System.out.println("ContentType:	"+contentType);
  		System.out.println("Content:");
  		System.out.println(response);
  		return this;
  	}
  	
  	public WebappTester statusCodeIs(int statusCode)
  	{
  		if(statusCode != this.statusCode) {
  			assertEquals("Status codes don't match.", statusCodeText(statusCode, null), statusCodeText(this.statusCode, response));
  		}
  		return this;
  	}
  	
  	public WebappTester contentTypeIs(String contentType)
  	{
  		if(!contentType.equals(this.contentType)) {
  			assertEquals("Content types don't match.", contentTypeText(contentType, null), contentTypeText(this.contentType, response));
  		}
  		return this;
  	}
  	
  	public WebappTester contentLengthIs(int contentLength)
  	{
  		assertEquals("Content lengths don't match.", contentLength, this.contentLength);
  		return this;
  	}
  	
  	public WebappTester characterEncodingIs(String characterEncoding)
  	{
  		if(!characterEncoding.equals(this.characterEncoding)) {
  			assertEquals("Character encodings don't match.", contentTypeText(characterEncoding, null), characterEncodingText(this.characterEncoding, response));
  		}
  		return this;
  	}
  	
  	public WebappTester responseIs(String response)
  	{
  		assertEquals("response wasnt the same", response, this.response);
  		return this;
  	}
  	
  	public WebappTester statusTextIs(String statusText)
  	{
  		assertEquals("response wasnt the same", statusText, this.statusText);
  		return this;
  	}
  	
  	public WebappTester responseContains(String response)
  	{
  		assertThat(this.response, containsString(response));
  		return this;
  	}
  	
  	public WebappTester responseDoesntContain(String response)
  	{
  		assertThat(this.response, not(containsString(response)));
  		return this;
  	}
  	
  	public WebappTester redirectUrlIs(String redirectPath)
  	{
  		httpResponse.getFirstHeader("Location").equals(redirectPath);
  		return this;
  	}
  	
  	
  	public WebappTester responseIsContentsOfFile(String filePath) throws IOException
  	{
  		return responseIsConcatenationOfFiles(new String[]{filePath}, "\n");
  	}
  	
  	public WebappTester responseIsConcatenationOfFiles(String[] filePaths) throws IOException
  	{
  		return responseIsConcatenationOfFiles(filePaths, "\n");
  	}
  	
  	public WebappTester responseIsConcatenationOfFiles(String[] filePaths, String delimiter) throws IOException
  	{
  