import static org.junit.Assert.*;
import org.junit.After;
import java.lang.management.*;
import java.io.*;
import java.net.*;
import javax.xml.xpath.*;
import org.xml.sax.InputSource;
import org.w3c.dom.NodeList;

public class SearchInHeap {
  String jhatPort = Integer.toString(7000 + Integer.parseInt(System.getProperty("org.gradle.test.worker")));
  String jhat;
  String hprof;
  boolean isSetup = false;
  // FIXME Change to false when we have enabled searchInHeapForByte
  boolean goDown = true;

  @After
  public void searchInHeapForChar() throws IOException, InterruptedException, XPathExpressionException {
    try {
      setupSearchInHeap();
      runOQL("select a.toString() from [C a where /really_secret_string/(a.toString())");
    }
    finally {
      tearDown();
    }
  }

  public void setupSearchInHeap() throws IOException, InterruptedException, XPathExpressionException {
    if (isSetup) {
      return;
    }
    String pid = ManagementFactory.getRuntimeMXBean().getName().replaceAll("@.*", "");
    String tmp = System.getProperty("temporaryDir");
    hprof = tmp + "/" + pid + ".hprof";
    jhat = "jhat -port " + jhatPort + " " + hprof;
    try {
      System.out.println("Dumping heap with jmap");
      Runtime.getRuntime().exec(new String[] {"jmap", String.format("-dump:format=b,file=%s", hprof), pid}).waitFor();

      System.out.println("Starting jhat");
      Process p=Runtime.getRuntime().exec(jhat);

      BufferedReader reader=new BufferedReader(new InputStreamReader(p.getInputStream()));
      String line=reader.readLine();
      while(!line.matches("Server is ready."))
      {
        line=reader.readLine();
      }
      System.out.println("jhat ready!");
      Thread.sleep(1000);
    }
    finally {
      isSetup = true;
    }
  }

  public void runOQL(String oql) throws IOException, InterruptedException, XPathExpressionException {
    System.out.println("Running OQL query...");
    URL oqlUrl = new URL("http://localhost:" + jhatPort + "/oql/?query=" + URLEncoder.encode(oql, "UTF-8"));
    URLConnection oqlConnection = oqlUrl.openConnection();
    BufferedReader in = new BufferedReader(new InputStreamReader(oqlConnection.getInputStream()));
    String inputLine;
    String xml = "";

    while ((inputLine = in.readLine()) != null)
      xml += inputLine;
    in.close();

    NodeList nodeList;
    try {
      // What I don't do just not to add an external dependency...
      xml = xml.replaceAll("(\\w+)=([^'\"][^ ]+?)([^'\"])", "$1='$2'$3");
      String xpath = "//table[@border=1]//td";
      XPath xPath = XPathFactory.newInstance().newXPath();
      nodeList = (NodeList) xPath.evaluate(xpath, new InputSource(new StringReader(xml)), XPathConstants.NODESET);
    }
    catch (javax.xml.xpath.XPathExpressionException e) {
      System.out.println(xml);
      throw e;
    }
    theAssert(nodeList.getLength());
  }

  public void tearDown() throws IOException, InterruptedException {
    if (goDown) {
      Runtime.getRuntime().exec(new String[] {"pkill", "-f", jhat}).waitFor();
      new File(hprof).delete();
    }
    else {
      goDown = true;
    }
  }

  void theAssert(int found) {
    assertEquals("Secret not found!", 0, found);
  }
}

@@ -778,32 +778,943 @@
 n();%0A    %7D%0A  %7D%0A%0A
+  // FIXME Add @After when SecurerString.secureErase(byte%5B%5D) is implemented%0A  public void searchInHeapForByte() throws IOException, InterruptedException, XPathExpressionException %7B%0A    try %7B%0A      setupSearchInHeap();%0A      runOQL(%22select %7B%22 +%0A             %22  obj:b,%22 +%0A             %22  value:(function(b) %7B%22 +%0A             %22    var a = '';%22 +%0A             %22    for (var i = 0; i %3C b.length; i++) %7B%22 +%0A             %22      a+=String.fromCharCode(b%5Bi%5D);%22 +%0A             %22    %7D%22 +%0A             %22    return escape(a);%22 +%0A             %22  %7D)(b)%22 +%0A             %22%7D %22 +%0A             %22from %5BB b where %22 +%0A             %22(function(b) %7B%22 +%0A             %22  var a = '';%22 +%0A             %22  for (var i = 0; i %3C b.length; i++) %7B%22 +%0A             %22    a+=String.fromCharCode(b%5Bi%5D);%22 +%0A             %22  %7D%22 +%0A             %22  return /really_secret_string/(a);%22 +%0A             %22%7D)(b)%22);%0A    %7D%0A    finally %7B%0A      tearDown();%0A    %7D%0A  %7D%0A%0A
   public void se

Add searchInHeapForByte but it's disabled for now