// This test has set response to JSON and pass StringHandle with format as JSON, expectint it to
  // work, logged an issue 82
  @Test
  public void testBulkSearchSQDwithResponseFormatandStringHandle() throws Exception {
    loadJSONDocuments();
    JSONDocumentManager docMgr = client.newJSONDocumentManager();

    QueryManager queryMgr = client.newQueryManager();
    StructuredQueryBuilder qb = new StructuredQueryBuilder();
    StructuredQueryDefinition qd = qb.and(qb.term("dog1", "dog11"));
    queryMgr.search(qd, new SearchHandle());

    docMgr.setNonDocumentFormat(Format.JSON);
    docMgr.setSearchView(QueryView.METADATA);
    docMgr.setMetadataCategories(Metadata.PERMISSIONS);

    StringHandle results = new StringHandle().withFormat(Format.JSON);
    DocumentPage page = docMgr.search(qd, 1, results);
    DocumentMetadataHandle mh = new DocumentMetadataHandle();
    while (page.hasNext()) {
      DocumentRecord rec = page.next();
      validateRecord(rec, Format.JSON);
      docMgr.readMetadata(rec.getUri(), mh);
      assertTrue("Records has permissions? ", mh.getPermissions().containsKey("flexrep-eval"));
      assertTrue("Record has collections ?", mh.getCollections().isEmpty());
    }
    assertFalse("Search handle contains", results.get().isEmpty());
  }
  @Test
  public void testFailedSearch() throws IOException {
    QueryManager queryMgr = Common.client.newQueryManager();
    StructuredQueryBuilder qb = queryMgr.newStructuredQueryBuilder();
    StructuredQueryDefinition qdef = qb.term("criteriaThatShouldNotMatchAnyDocument");

    SearchHandle results = queryMgr.search(qdef, new SearchHandle());
    assertNotNull(results);

    MatchDocumentSummary[] summaries = results.getMatchResults();
    assertTrue(summaries == null || summaries.length == 0);
  }
 // This test is to verify extract-document-data & extract-path with  selected=exclude option query
 @Test
 public void testExtractDocumentData2() throws Exception {
   this.loadJSONDocuments();
   this.loadXMLDocuments();
   String head = "<search:search xmlns:search=\"http://marklogic.com/appservices/search\">";
   String tail = "</search:search>";
   String qtext4 = "<search:qtext>71 OR dog14</search:qtext>";
   DocumentManager docMgr = client.newDocumentManager();
   QueryManager queryMgr = client.newQueryManager();
   String options =
       "<search:options>"
           + "<search:extract-document-data selected=\"exclude\">"
           + "<search:extract-path>//foo</search:extract-path>"
           + "<search:extract-path>//says</search:extract-path>"
           + "</search:extract-document-data>"
           + "</search:options>";
   // test XML response with extracted XML and JSON matches
   String combinedSearch = head + qtext4 + options + tail;
   RawCombinedQueryDefinition rawCombinedQueryDefinition =
       queryMgr.newRawCombinedQueryDefinition(
           new StringHandle(combinedSearch).withMimetype("application/xml"));
   SearchHandle results = queryMgr.search(rawCombinedQueryDefinition, new SearchHandle());
   MatchDocumentSummary[] summaries = results.getMatchResults();
   assertNotNull(summaries);
   assertEquals(2, summaries.length);
   for (MatchDocumentSummary summary : summaries) {
     ExtractedResult extracted = summary.getExtracted();
     if (Format.XML == summary.getFormat()) {
       // we don't test for kind because it isn't sent in this case
       System.out.println("EXTRACTED Size ==" + extracted.size());
       // TODO:: Bug 33921 also add test to include-with-ancestors
       assertEquals(0, extracted.size());
       //			Document item1 = extracted.next().getAs(Document.class);
       //			assertEquals("This is so foo with a bar 71", item1.getFirstChild().getTextContent());
       continue;
     } else if (Format.JSON == summary.getFormat()) {
       // we don't test for kind because it isn't sent in this case
       assertEquals(1, extracted.size());
       for (ExtractedItem item : extracted) {
         String stringJsonItem = item.getAs(String.class);
         JsonNode nodeJsonItem = item.getAs(JsonNode.class);
         if (nodeJsonItem.has("animal")) {
           assertEquals("{\"animal\":\"dog14\"}", stringJsonItem);
           continue;
         }
         fail("unexpected extracted item:" + stringJsonItem);
       }
       continue;
     }
     fail("unexpected search result:" + summary.getUri());
   }
 }
  @Test
  public void testJSON() {
    QueryManager queryMgr = Common.client.newQueryManager();
    StructuredQueryBuilder qb = queryMgr.newStructuredQueryBuilder();
    StructuredQueryDefinition t = qb.term("leaf3");

    // create a handle for the search results
    StringHandle resultsHandle = new StringHandle().withFormat(Format.JSON);

    // run the search
    queryMgr.search(t, resultsHandle);

    assertEquals("{", resultsHandle.get().substring(0, 1)); // It's JSON, right?
  }
  // This test is testing SearchView options and search handle
  @Test
  public void testBulkSearchSQDwithJSONResponseFormat() throws Exception {

    loadJSONDocuments();
    JSONDocumentManager docMgr = client.newJSONDocumentManager();

    QueryManager queryMgr = client.newQueryManager();
    StructuredQueryBuilder qb = new StructuredQueryBuilder();
    StructuredQueryDefinition qd = qb.and(qb.term("woof"));
    docMgr.setNonDocumentFormat(Format.JSON);

    docMgr.setSearchView(QueryView.FACETS);
    JacksonHandle jh = new JacksonHandle();
    docMgr.search(qd, 1, jh);

    //		System.out.println(jh.get().toString());
    assertTrue("Searh response has entry for facets", jh.get().has("facets"));
    assertFalse(
        "Searh response has entry for facets",
        jh.get().has("results")); // Issue 84 is tracking this
    assertFalse("Searh response has entry for facets", jh.get().has("metrics"));

    docMgr.setSearchView(QueryView.RESULTS);
    docMgr.search(qd, 1, jh);

    assertFalse("Searh response has entry for facets", jh.get().has("facets"));
    assertTrue("Searh response has entry for facets", jh.get().has("results"));
    assertFalse(
        "Searh response has entry for facets",
        jh.get().has("metrics")); // Issue 84 is tracking this

    docMgr.setSearchView(QueryView.METADATA);
    docMgr.search(qd, 1, jh);

    assertFalse("Searh response has entry for facets", jh.get().has("facets"));
    assertFalse("Searh response has entry for facets", jh.get().has("results"));
    assertTrue("Searh response has entry for facets", jh.get().has("metrics"));

    docMgr.setSearchView(QueryView.ALL);
    docMgr.search(qd, 1, jh);

    assertTrue("Searh response has entry for facets", jh.get().has("facets"));
    assertTrue("Searh response has entry for facets", jh.get().has("results"));
    assertTrue("Searh response has entry for facets", jh.get().has("metrics"));

    queryMgr.setView(QueryView.FACETS);
    queryMgr.search(qd, jh);
    System.out.println(jh.get().toString());
  }
  @Test
  public void testExtractMetadata() throws SAXException, IOException {
    QueryManager queryMgr = Common.client.newQueryManager();

    String combined =
        "<search xmlns=\"http://marklogic.com/appservices/search\">"
            + "<query>"
            + "<value-query>"
            + "<element ns=\"http://marklogic.com/xdmp/json\" name=\"firstKey\"/>"
            + "<text>first value</text>"
            + "</value-query>"
            + "</query>"
            + "<options>"
            + "<extract-metadata>"
            + "<qname elem-ns=\"http://marklogic.com/xdmp/json\" elem-name=\"subKey\"/>"
            + "</extract-metadata>"
            + "</options>"
            + "</search>";
    StringHandle rawHandle = new StringHandle(combined);

    RawCombinedQueryDefinition rawDef = queryMgr.newRawCombinedQueryDefinition(rawHandle);

    SearchHandle sh = queryMgr.search(rawDef, new SearchHandle());

    MatchDocumentSummary[] summaries = sh.getMatchResults();
    assertNotNull(summaries);
    assertEquals("expected 1 result", 1, summaries.length);

    MatchDocumentSummary matchResult = summaries[0];
    Document metadata = matchResult.getMetadata();
    Element subKey =
        (Element)
            metadata.getElementsByTagNameNS("http://marklogic.com/xdmp/json", "subKey").item(0);
    assertEquals("string", subKey.getAttribute("type"));
    assertEquals("sub value", subKey.getTextContent());

    String docStr = Common.testDocumentToString(metadata);
    String handleStr = matchResult.getMetadata(new StringHandle()).get();
    assertXMLEqual("Different metadata for handle", docStr, handleStr);

    Document snippet = matchResult.getSnippets()[0];
    docStr = Common.testDocumentToString(snippet);
    handleStr = matchResult.getSnippetIterator(new StringHandle()).next().get();
    assertXMLEqual("Different snippet for handle", docStr, handleStr);
  }
  @Test
  public void testStructuredSearch2() throws IOException {
    QueryManager queryMgr = Common.client.newQueryManager();

    EditableNamespaceContext namespaces = new EditableNamespaceContext();
    namespaces.put("x", "root.org");
    namespaces.put("y", "target.org");
    StructuredQueryBuilder qb = new StructuredQueryBuilder(namespaces);

    StructuredQueryDefinition qdef =
        qb.geospatial(qb.geoPath(qb.pathIndex("/x:geo/y:path")), qb.box(1, 2, 3, 4));

    SearchHandle results = queryMgr.search(qdef, new SearchHandle());
    assertNotNull(results);

    MatchDocumentSummary[] summaries = results.getMatchResults();
    assertTrue(summaries == null || summaries.length == 0);
  }
  @Test
  public void testStructuredSearch() throws IOException {
    QueryManager queryMgr = Common.client.newQueryManager();
    StructuredQueryBuilder qb = queryMgr.newStructuredQueryBuilder();

    for (QueryDefinition t :
        new QueryDefinition[] {qb.term("leaf3"), qb.build(qb.value(qb.element("leaf"), "leaf3"))}) {
      SearchHandle results = queryMgr.search(t, new SearchHandle());
      assertNotNull(results);
      assertFalse(results.getMetrics().getTotalTime() == -1);

      MatchDocumentSummary[] summaries = results.getMatchResults();
      assertNotNull(summaries);
      assertEquals("expected 1 result", 1, summaries.length);
      for (MatchDocumentSummary summary : summaries) {
        MatchLocation[] locations = summary.getMatchLocations();
        assertEquals("expected 1 match location", 1, locations.length);
        for (MatchLocation location : locations) {
          assertNotNull(location.getAllSnippetText());
        }
      }
    }
  }
  /* Searching for boolean and string in XML element using value query.
   * Purpose: To validate QueryBuilder's new value methods (in 8.0) in XML document using an element.
   *
   * Load a file that has a boolean value in a XML attribute and use query def to search on that boolean value
   *
   * Methods used : value(StructuredQueryBuilder.TextIndex index, boolean)
   *                value(StructuredQueryBuilder.TextIndex index, String)
   */
  @Test
  public void testQueryBuilderValueWithBooleanAndString()
      throws XpathException, SAXException, IOException {

    String docId[] = {"play-persons.xml"};

    TextDocumentManager docMgr = client.newTextDocumentManager();
    QueryManager queryMgr = client.newQueryManager();
    DocumentWriteSet writeset = docMgr.newWriteSet();

    // Put meta-data

    DocumentMetadataHandle metadataHandle = new DocumentMetadataHandle();
    metadataHandle.getCollections().addAll("my-collection1", "my-collection2");
    metadataHandle.getPermissions().add("app-user", Capability.UPDATE, Capability.READ);
    metadataHandle.getProperties().put("reviewed", true);
    metadataHandle.getProperties().put("myString", "foo");
    metadataHandle.getProperties().put("myInteger", 10);
    metadataHandle.getProperties().put("myDecimal", 34.56678);
    metadataHandle.getProperties().put("myCalendar", Calendar.getInstance().get(Calendar.YEAR));
    metadataHandle.setQuality(23);

    writeset.addDefault(metadataHandle);

    // Create a new document using StringHandle
    StringBuffer strBuf = new StringBuffer();

    strBuf.append("<PLAY>");
    strBuf.append("<TITLE>All's Well That Ends Well</TITLE>");
    strBuf.append("<PERSONAE>");
    strBuf.append("<TITLE>Dramatis Personae</TITLE>");

    strBuf.append("<PGROUP>");
    strBuf.append("<subgroup>true</subgroup>");

    strBuf.append("<PERSONA>KING OF FRANCE</PERSONA>");
    strBuf.append("<PERSONA>DUKE OF FLORENCE</PERSONA>");
    strBuf.append("<PERSONA>BERTRAM, Count of Rousillon.</PERSONA>");
    strBuf.append("<PERSONA>LAFEU, an old lord.</PERSONA>");
    strBuf.append("</PGROUP>");

    strBuf.append("<PGROUP>");
    strBuf.append("<subgroup>false</subgroup>");

    strBuf.append("<PERSONA>PAROLLES, a follower of Bertram.</PERSONA>");
    strBuf.append("<PERSONA>A Page. </PERSONA>");
    strBuf.append("</PGROUP>");

    strBuf.append("<PGROUP>");
    strBuf.append("<subgroup>false</subgroup>");
    strBuf.append("<PERSONA>COUNTESS OF ROUSILLON, mother to Bertram. </PERSONA>");
    strBuf.append("<PERSONA>HELENA, a gentlewoman protected by the Countess.</PERSONA>");
    strBuf.append("<PERSONA>An old Widow of Florence. </PERSONA>");
    strBuf.append("<PERSONA>DIANA, daughter to the Widow.</PERSONA>");
    strBuf.append("</PGROUP>");

    strBuf.append("<PGROUP>");
    strBuf.append("<subgroup>false</subgroup>");
    strBuf.append("<PERSONA>VIOLENTA</PERSONA>");
    strBuf.append("<PERSONA>MARIANA</PERSONA>");
    strBuf.append("<GRPDESCR>neighbours and friends to the Widow.</GRPDESCR>");
    strBuf.append("</PGROUP>");

    strBuf.append("<PERSONA>Lords, Officers, Soldiers, &amp;c., French and Florentine.</PERSONA>");
    strBuf.append("</PERSONAE>");
    strBuf.append("</PLAY>");

    writeset.add("/1/" + docId[0], new StringHandle().with(strBuf.toString()));
    docMgr.write(writeset);

    docMgr.write(writeset);

    // Search for the range with attribute value true in rangeRelativeBucketConstraintOpt.xml
    // document.
    StructuredQueryBuilder qb = new StructuredQueryBuilder();

    // Build an object that represents StructuredQueryBuilder.ElementAttribute for use in values
    // method
    // that is of type StructuredQueryBuilder.TextIndex

    QueryDefinition qd = qb.value(qb.element("subgroup"), false);

    // Create handle for the result
    StringHandle resultsHandle = new StringHandle().withFormat(Format.XML);
    queryMgr.search(qd, resultsHandle);

    // Get the result
    String resultDoc = resultsHandle.get();

    System.out.println(resultDoc);
    // Verify that search response has found 1 element attribute
    assertXpathEvaluatesTo(
        "fn:doc(\"/1/play-persons.xml\")",
        "string(//*[local-name()='response']//*[local-name()='result']//@*[local-name()='path'])",
        resultDoc);
    assertXpathEvaluatesTo(
        "3", "count(//*[local-name()='response']//*[local-name()='match'])", resultDoc);

    // Search for the following royal (XML ELEMENT) in all-well.xml document.
    StructuredQueryBuilder qbStr = new StructuredQueryBuilder();
    QueryDefinition qdStr =
        qbStr.value(
            qbStr.element("PERSONA"),
            "KING OF FRANCE",
            "DUKE OF FLORENCE",
            "BERTRAM, Count of Rousillon.",
            "LAFEU, an old lord.");

    // Create handle for the result
    StringHandle resultsHandleStr = new StringHandle().withFormat(Format.XML);
    queryMgr.search(qdStr, resultsHandleStr);

    // Get the result
    String resultDocStr = resultsHandleStr.get();

    System.out.println(resultDocStr);
    // Verify that search response has found 4 PERSONA elements under /PLAY/PERSONAE
    assertXpathEvaluatesTo(
        "fn:doc(\"/1/play-persons.xml\")",
        "string(//*[local-name()='response']//*[local-name()='result']//@*[local-name()='path'])",
        resultDocStr);
    assertXpathEvaluatesTo(
        "4", "count(//*[local-name()='response']//*[local-name()='match'])", resultDocStr);
  }
  @Test
  public void testWithVariousGrammarAndWordQuery()
      throws IOException, ParserConfigurationException, SAXException, XpathException {
    System.out.println("Running testWithVariousGrammarAndWordQuery");

    String[] filenames = {
      "constraint1.xml", "constraint2.xml", "constraint3.xml", "constraint4.xml", "constraint5.xml"
    };
    String queryOptionName = "absRangeConstraintWithVariousGrammarAndWordQueryOpt.xml";

    DatabaseClient client =
        DatabaseClientFactory.newClient(
            "localhost", 8011, "rest-admin", "x", Authentication.DIGEST);

    // write docs
    for (String filename : filenames) {
      writeDocumentUsingInputStreamHandle(client, filename, "/abs-range-constraint/", "XML");
    }

    setQueryOption(client, queryOptionName);

    QueryManager queryMgr = client.newQueryManager();

    // create query def
    StringQueryDefinition querydef = queryMgr.newStringDefinition(queryOptionName);
    querydef.setCriteria("(pop:high OR pop:medium) AND price:medium AND intitle:served");

    // create handle
    DOMHandle resultsHandle = new DOMHandle();
    queryMgr.search(querydef, resultsHandle);

    // get the result
    Document resultDoc = resultsHandle.get();

    assertXpathEvaluatesTo(
        "1", "string(//*[local-name()='result'][last()]//@*[local-name()='index'])", resultDoc);
    assertXpathEvaluatesTo(
        "Vannevar served",
        "string(//*[local-name()='result'][1]//*[local-name()='title'])",
        resultDoc);
    assertXpathEvaluatesTo(
        "12.34", "string(//*[local-name()='result'][1]//@*[local-name()='amt'])", resultDoc);
    assertXpathEvaluatesTo(
        "5", "string(//*[local-name()='result'][1]//*[local-name()='popularity'])", resultDoc);
    assertXpathEvaluatesTo(
        "1", "string(//*[local-name()='facet-value']//@*[local-name()='count'])", resultDoc);
    assertXpathEvaluatesTo("High", "string(//*[local-name()='facet-value'])", resultDoc);

    // String expectedSearchReport = "(cts:search(fn:collection(),
    // cts:and-query((cts:or-query((cts:element-range-query(fn:QName(\"\", \"popularity\"),
    // \"&gt;=\", xs:int(\"5\"), (), 1), cts:and-query((cts:element-range-query(fn:QName(\"\",
    // \"popularity\"), \"&gt;=\", xs:int(\"3\"), (), 1), cts:element-range-query(fn:QName(\"\",
    // \"popularity\"), \"&lt;\", xs:int(\"5\"), (), 1)), ()))),
    // cts:element-attribute-range-query(fn:QName(\"http://cloudbank.com\", \"price\"),
    // fn:QName(\"\", \"amt\"), \"&gt;=\", 3.0, (), 1),
    // cts:element-attribute-range-query(fn:QName(\"http://cloudbank.com\", \"price\"),
    // fn:QName(\"\", \"amt\"), \"&lt;\", 14.0, (), 1), cts:element-word-query(fn:QName(\"\",
    // \"title\"), \"served\", (\"lang=en\"), 1)), ()), (\"score-logtfidf\"), 1))[1 to 10]";

    // assertXpathEvaluatesTo(expectedSearchReport, "string(//*[local-name()='report'])",
    // resultDoc);

    // release client
    client.release();
  }