@Test
  public void testTerminalClauseTwoSearchHandlersDifferent() throws Exception {
    final TerminalClause input1 = new TerminalClauseImpl("field", Operator.EQUALS, "Value1");
    final TerminalClause input2 = new TerminalClauseImpl("field", Operator.EQUALS, "Value2");
    final SearchHandlerManager manager = mockController.getMock(SearchHandlerManager.class);

    final ClausePermissionHandler permissionHandler =
        mockController.getMock(ClausePermissionHandler.class);
    EasyMock.expect(permissionHandler.sanitise(null, input1)).andReturn(input1);
    EasyMock.expect(permissionHandler.sanitise(null, input1)).andReturn(input2);

    final ClauseHandler handler1 = new MockClauseHandler(null, null, permissionHandler, null);
    final ClauseHandler handler2 = new MockClauseHandler(null, null, permissionHandler, null);

    EasyMock.expect(manager.getClauseHandler((User) null, "field"))
        .andReturn(CollectionBuilder.newBuilder(handler1, handler2).asList());

    final JqlOperandResolver jqlOperandResolver = mockController.getMock(JqlOperandResolver.class);

    mockController.replay();

    ClauseSanitisingVisitor visitor =
        new ClauseSanitisingVisitor(manager, jqlOperandResolver, null) {
          @Override
          TerminalClause sanitiseOperands(final TerminalClause clause) {
            return clause;
          }
        };

    final Clause expected = new OrClause(input1, input2);
    final Clause clause = input1.accept(visitor);
    assertEquals(expected, clause);

    mockController.verify();
  }
  @Test
  public void testTerminalClauseOneSearchHandler() throws Exception {
    final TerminalClause input = new TerminalClauseImpl("field", Operator.EQUALS, "Value");
    final SearchHandlerManager manager = mockController.getMock(SearchHandlerManager.class);

    final ClausePermissionHandler permissionHandler =
        mockController.getMock(ClausePermissionHandler.class);
    EasyMock.expect(permissionHandler.sanitise(null, input)).andReturn(input);

    final ClauseHandler handler = new MockClauseHandler(null, null, permissionHandler, null);
    EasyMock.expect(manager.getClauseHandler((User) null, "field"))
        .andReturn(Collections.singletonList(handler));

    final JqlOperandResolver jqlOperandResolver = mockController.getMock(JqlOperandResolver.class);

    mockController.replay();

    ClauseSanitisingVisitor visitor =
        new ClauseSanitisingVisitor(manager, jqlOperandResolver, null) {
          @Override
          TerminalClause sanitiseOperands(final TerminalClause clause) {
            return clause;
          }
        };

    final Clause clause = input.accept(visitor);
    assertSame(clause, input);

    mockController.verify();
  }
  private Set<Project> getAssociatedProjectsFromClause(
      final User searcher, final TerminalClause clause) {
    final Set<Project> allVisibleProjects =
        new HashSet<Project>(permissionManager.getProjectObjects(Permissions.BROWSE, searcher));
    Set<Project> associatedProjects = new HashSet<Project>();

    final List<QueryLiteral> list =
        jqlOperandResolver.getValues(searcher, clause.getOperand(), clause);
    final Set<QueryLiteral> rawValues =
        list != null ? new LinkedHashSet<QueryLiteral>(list) : new LinkedHashSet<QueryLiteral>();
    // if we are negating, we need to exclude projects with no category
    // e.g. category NOT IN ("cat1") is equivalent to category NOT IN ("cat1", EMPTY)
    if (isNegationOperator(clause.getOperator())) {
      rawValues.add(new QueryLiteral());
    }

    for (QueryLiteral rawValue : rawValues) {
      final Collection<Project> projectsForCategory =
          projectCategoryResolver.getProjectsForCategory(rawValue);
      associatedProjects.addAll(
          CollectionUtils.intersection(allVisibleProjects, projectsForCategory));
    }

    if (!associatedProjects.isEmpty()) {
      // if we have a negation operator we want every project context barr the associated ones.
      if (isNegationOperator(clause.getOperator())) {
        allVisibleProjects.removeAll(associatedProjects);
        associatedProjects = allVisibleProjects;
      }
    }

    return associatedProjects;
  }
 @Nonnull
 public QueryFactoryResult getQuery(
     @Nonnull final QueryCreationContext queryCreationContext,
     @Nonnull final TerminalClause terminalClause) {
   if (SystemSearchConstants.forAttachments()
       .getSupportedOperators()
       .contains(terminalClause.getOperator())) {
     return new QueryFactoryResult(
         new TermQuery(
             new Term(
                 DocumentConstants.ISSUE_ATTACHMENT, getTermText(terminalClause.getOperator()))));
   } else {
     log.debug("Attempt to search attachments when attachments are disabled.");
     return createFalseResult();
   }
 }
  public ClauseContext getClauseContext(final User searcher, final TerminalClause terminalClause) {
    final Operator operator = terminalClause.getOperator();
    if (!handlesOperator(operator)) {
      return ClauseContextImpl.createGlobalClauseContext();
    }

    final List<QueryLiteral> values =
        jqlOperandResolver.getValues(searcher, terminalClause.getOperand(), terminalClause);
    Set<String> issueTypeIds = new HashSet<String>();
    if (values != null) {
      for (QueryLiteral value : values) {
        // if we have an empty literal, the Global context will not impact on any existing contexts,
        // so do nothing
        if (!value.isEmpty()) {
          issueTypeIds.addAll(getIds(value));
        }
      }
    }

    if (!issueTypeIds.isEmpty() && isNegationOperator(operator)) {
      final Set<String> allIssueTypes = new HashSet<String>(constantsManager.getAllIssueTypeIds());
      allIssueTypes.removeAll(issueTypeIds);
      issueTypeIds = allIssueTypes;
    }

    if (issueTypeIds.isEmpty()) {
      return ClauseContextImpl.createGlobalClauseContext();
    }

    final Set<ProjectIssueTypeContext> contexts = new HashSet<ProjectIssueTypeContext>();
    for (String issueTypeId : issueTypeIds) {
      contexts.add(
          new ProjectIssueTypeContextImpl(
              AllProjectsContext.INSTANCE, new IssueTypeContextImpl(issueTypeId)));
    }

    return new ClauseContextImpl(contexts);
  }
  public ClauseContext getClauseContext(final User searcher, final TerminalClause terminalClause) {
    final Operator operator = terminalClause.getOperator();

    if (!handlesOperator(operator)) {
      return ClauseContextImpl.createGlobalClauseContext();
    }

    final Set<Project> associatedProjects =
        getAssociatedProjectsFromClause(searcher, terminalClause);
    final Set<ProjectIssueTypeContext> contexts = getContextsForProjects(associatedProjects);
    return contexts.isEmpty()
        ? ClauseContextImpl.createGlobalClauseContext()
        : new ClauseContextImpl(contexts);
  }
  public ClauseContext getClauseContext(final User searcher, final TerminalClause terminalClause) {
    final Operator operator = terminalClause.getOperator();
    boolean isEquality = isEqualityOperator(operator);

    if (!handlesOperator(operator)) {
      return ClauseContextImpl.createGlobalClauseContext();
    }

    final Set<ProjectIssueTypeContext> projectIssueTypeContexts =
        getContextFromStatusValues(searcher, terminalClause, isEquality);

    return projectIssueTypeContexts.isEmpty()
        ? ClauseContextImpl.createGlobalClauseContext()
        : new ClauseContextImpl(projectIssueTypeContexts);
  }
 /**
  * @param searcher the user performing the search
  * @param clause the clause
  * @return a set of Strings representing the ids of the statuses; never null.
  */
 Set<String> getIds(final User searcher, final TerminalClause clause) {
   final List<QueryLiteral> literals =
       jqlOperandResolver.getValues(searcher, clause.getOperand(), clause);
   Set<String> ids = new HashSet<String>();
   if (literals != null) {
     for (QueryLiteral literal : literals) {
       if (literal.getLongValue() != null) {
         ids.addAll(issueConstantInfoResolver.getIndexedValues(literal.getLongValue()));
       } else if (literal.getStringValue() != null) {
         ids.addAll(issueConstantInfoResolver.getIndexedValues(literal.getStringValue()));
       } else if (literal.isEmpty()) {
         // empty literals would generate a Global context, but this does not impact on other
         // contexts
       }
     }
   }
   return ids;
 }