@Test
  public void search_by_characteristics() throws InterruptedException {
    CharacteristicDto char1 = DebtTesting.newCharacteristicDto("RELIABILITY");
    db.debtCharacteristicDao().insert(char1, dbSession);

    CharacteristicDto char11 =
        DebtTesting.newCharacteristicDto("SOFT_RELIABILITY").setParentId(char1.getId());
    db.debtCharacteristicDao().insert(char11, dbSession);
    dbSession.commit();

    dao.insert(
        dbSession,
        RuleTesting.newDto(RuleKey.of("java", "S001")).setSubCharacteristicId(char11.getId()));

    dao.insert(dbSession, RuleTesting.newDto(RuleKey.of("javascript", "S002")));

    dbSession.commit();
    dbSession.clearCache();

    RuleQuery query;
    Result<Rule> results;

    // 0. we have 2 rules in index
    results = index.search(new RuleQuery(), new QueryContext());
    assertThat(results.getHits()).hasSize(2);

    // filter by non-subChar
    query = new RuleQuery().setDebtCharacteristics(ImmutableSet.of("toto"));
    assertThat(index.search(query, new QueryContext()).getHits()).isEmpty();

    // filter by subChar
    query = new RuleQuery().setDebtCharacteristics(ImmutableSet.of(char11.getKey()));
    assertThat(index.search(query, new QueryContext()).getHits()).hasSize(1);

    // filter by Char
    query = new RuleQuery().setDebtCharacteristics(ImmutableSet.of(char1.getKey()));
    assertThat(index.search(query, new QueryContext()).getHits()).hasSize(1);

    // filter by Char and SubChar
    query =
        new RuleQuery().setDebtCharacteristics(ImmutableSet.of(char11.getKey(), char1.getKey()));
    assertThat(index.search(query, new QueryContext()).getHits()).hasSize(1);

    // match by Char
    query = new RuleQuery().setQueryText(char1.getKey());
    assertThat(index.search(query, new QueryContext()).getHits()).hasSize(1);

    // match by SubChar
    query = new RuleQuery().setQueryText(char11.getKey());
    assertThat(index.search(query, new QueryContext()).getHits()).hasSize(1);

    // match by SubChar & Char
    query = new RuleQuery().setQueryText(char11.getKey() + " " + char1.getKey());
    assertThat(index.search(query, new QueryContext()).getHits()).hasSize(1);
  }
  private void insertDebtCharacteristics(DbSession dbSession) {
    CharacteristicDto reliability = DebtTesting.newCharacteristicDto("RELIABILITY");
    db.debtCharacteristicDao().insert(dbSession, reliability);

    CharacteristicDto softReliability =
        DebtTesting.newCharacteristicDto("SOFT_RELIABILITY").setParentId(reliability.getId());
    db.debtCharacteristicDao().insert(dbSession, softReliability);
    softReliabilityId = softReliability.getId();

    CharacteristicDto hardReliability =
        DebtTesting.newCharacteristicDto("HARD_RELIABILITY").setParentId(reliability.getId());
    db.debtCharacteristicDao().insert(dbSession, hardReliability);
    hardReliabilityId = hardReliability.getId();
  }
  @Test
  public void search_by_has_debt_characteristic() throws InterruptedException {
    CharacteristicDto char1 =
        DebtTesting.newCharacteristicDto("c1").setEnabled(true).setName("char1");
    db.debtCharacteristicDao().insert(char1, dbSession);
    dbSession.commit();

    CharacteristicDto char11 =
        DebtTesting.newCharacteristicDto("c11")
            .setEnabled(true)
            .setName("char11")
            .setParentId(char1.getId());
    db.debtCharacteristicDao().insert(char11, dbSession);

    // Rule with default characteristic
    dao.insert(
        dbSession,
        RuleTesting.newDto(RuleKey.of("findbugs", "S001"))
            .setSubCharacteristicId(null)
            .setRemediationFunction(null)
            .setDefaultSubCharacteristicId(char11.getId())
            .setDefaultRemediationFunction("LINEAR")
            .setDefaultRemediationCoefficient("2h"));
    // Rule with overridden characteristic
    dao.insert(
        dbSession,
        RuleTesting.newDto(RuleKey.of("pmd", "S002"))
            .setSubCharacteristicId(char11.getId())
            .setRemediationFunction("LINEAR")
            .setRemediationCoefficient("2h")
            .setDefaultSubCharacteristicId(null)
            .setDefaultRemediationFunction(null));
    dbSession.commit();

    // 0. assert base case
    assertThat(index.search(new RuleQuery(), new QueryContext()).getTotal()).isEqualTo(2);
    assertThat(db.debtCharacteristicDao().selectCharacteristics()).hasSize(2);

    // 1. assert hasSubChar filter
    assertThat(
            index
                .search(new RuleQuery().setHasDebtCharacteristic(true), new QueryContext())
                .getTotal())
        .isEqualTo(2);
  }
  @Test
  public void search_by_characteristics_with_default_and_overridden_char()
      throws InterruptedException {
    CharacteristicDto char1 = DebtTesting.newCharacteristicDto("RELIABILITY");
    db.debtCharacteristicDao().insert(char1, dbSession);

    CharacteristicDto char11 =
        DebtTesting.newCharacteristicDto("SOFT_RELIABILITY").setParentId(char1.getId());
    db.debtCharacteristicDao().insert(char11, dbSession);
    dbSession.commit();

    CharacteristicDto char2 = DebtTesting.newCharacteristicDto("TESTABILITY");
    db.debtCharacteristicDao().insert(char2, dbSession);

    CharacteristicDto char21 =
        DebtTesting.newCharacteristicDto("UNIT_TESTABILITY").setParentId(char2.getId());
    db.debtCharacteristicDao().insert(char21, dbSession);
    dbSession.commit();

    // Rule with only default sub characteristic -> should be find by char11 and char1
    dao.insert(
        dbSession,
        RuleTesting.newDto(RuleKey.of("java", "S001"))
            .setSubCharacteristicId(char11.getId())
            .setDefaultSubCharacteristicId(null));

    // Rule with only sub characteristic -> should be find by char11 and char1
    dao.insert(
        dbSession,
        RuleTesting.newDto(RuleKey.of("java", "S002"))
            .setSubCharacteristicId(null)
            .setDefaultSubCharacteristicId(char11.getId()));

    // Rule with both default sub characteristic and overridden sub characteristic -> should only be
    // find by char21 and char2
    dao.insert(
            dbSession,
            RuleTesting.newDto(RuleKey.of("java", "S003")).setSubCharacteristicId(char21.getId()))
        .setDefaultSubCharacteristicId(char11.getId());

    // Rule with both default sub characteristic and overridden sub characteristic and with same
    // values -> should be find by char11 and char1
    dao.insert(
            dbSession,
            RuleTesting.newDto(RuleKey.of("java", "S004")).setSubCharacteristicId(char11.getId()))
        .setDefaultSubCharacteristicId(char11.getId());

    dbSession.commit();
    dbSession.clearCache();

    RuleQuery query;
    Result<Rule> results;

    // 0. we have 4 rules in index
    results = index.search(new RuleQuery(), new QueryContext());
    assertThat(results.getHits()).hasSize(4);

    // filter by subChar
    query = new RuleQuery().setDebtCharacteristics(ImmutableSet.of(char11.getKey()));
    assertThat(ruleKeys(index.search(query, new QueryContext()).getHits()))
        .containsOnly("S001", "S002", "S004");

    query = new RuleQuery().setDebtCharacteristics(ImmutableSet.of(char21.getKey()));
    assertThat(ruleKeys(index.search(query, new QueryContext()).getHits())).containsOnly("S003");

    // filter by Char
    query = new RuleQuery().setDebtCharacteristics(ImmutableSet.of(char1.getKey()));
    assertThat(ruleKeys(index.search(query, new QueryContext()).getHits()))
        .containsOnly("S001", "S002", "S004");

    query = new RuleQuery().setDebtCharacteristics(ImmutableSet.of(char2.getKey()));
    assertThat(ruleKeys(index.search(query, new QueryContext()).getHits())).containsOnly("S003");

    // filter by Char and SubChar
    query =
        new RuleQuery()
            .setDebtCharacteristics(
                ImmutableSet.of(char11.getKey(), char1.getKey(), char2.getKey(), char21.getKey()));
    assertThat(ruleKeys(index.search(query, new QueryContext()).getHits()))
        .containsOnly("S001", "S002", "S003", "S004");
  }