@Test
  public void delete_characteristic() {
    DbSession batchSession = mock(DbSession.class);
    when(dbClient.openSession(true)).thenReturn(batchSession);

    when(ruleDao.findRulesByDebtSubCharacteristicId(batchSession, subCharacteristicDto.getId()))
        .thenReturn(
            newArrayList(
                new RuleDto()
                    .setSubCharacteristicId(subCharacteristicDto.getId())
                    .setRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.toString())
                    .setRemediationCoefficient("2h")
                    .setRemediationOffset("5min")));
    when(dao.selectCharacteristicsByParentId(1, batchSession))
        .thenReturn(newArrayList(subCharacteristicDto));
    when(dao.selectById(1, batchSession)).thenReturn(characteristicDto);

    service.delete(1);

    verify(ruleDao).update(eq(batchSession), ruleCaptor.capture());

    verify(dao, times(2)).update(characteristicCaptor.capture(), eq(batchSession));
    CharacteristicDto subCharacteristicDto = characteristicCaptor.getAllValues().get(0);
    CharacteristicDto characteristicDto = characteristicCaptor.getAllValues().get(1);

    // Sub characteristic is disable
    assertThat(subCharacteristicDto.getId()).isEqualTo(2);
    assertThat(subCharacteristicDto.isEnabled()).isFalse();
    assertThat(subCharacteristicDto.getUpdatedAt()).isEqualTo(now);

    // Characteristic is disable
    assertThat(characteristicDto.getId()).isEqualTo(1);
    assertThat(characteristicDto.isEnabled()).isFalse();
    assertThat(characteristicDto.getUpdatedAt()).isEqualTo(now);
  }
  @Test
  public void fail_to_create_sub_characteristic_when_name_already_used() {
    when(dao.selectByName("Compilation", session)).thenReturn(new CharacteristicDto());
    when(dao.selectById(1, session)).thenReturn(characteristicDto);

    try {
      service.create("Compilation", 1);
      fail();
    } catch (BadRequestException e) {
      assertThat(e.firstError().getKey()).isEqualTo("errors.is_already_used");
      assertThat(e.firstError().getParams()[0]).isEqualTo("Compilation");
    }
  }
  @Test
  public void
      index_overridden_function_if_both_default_and_overridden_functions_exists_when_indexing_rules() {
    when(ruleDao.selectEnablesAndNonManual(session))
        .thenReturn(
            newArrayList(
                new RuleDto()
                    .setId(10)
                    .setRepositoryKey("repo")
                    .setRuleKey("key1")
                    .setSeverity(Severity.MINOR)
                    // default and overridden debt values are set
                    .setDefaultSubCharacteristicId(11)
                    .setDefaultRemediationFunction("CONSTANT_ISSUE")
                    .setDefaultRemediationOffset("15min")
                    .setSubCharacteristicId(11)
                    .setRemediationFunction("LINEAR")
                    .setRemediationCoefficient("1h")));

    when(characteristicDao.selectCharacteristicsByIds(newHashSet(11), session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(11)
                    .setKey("MODULARITY")
                    .setName("Modularity")
                    .setParentId(10)));
    when(characteristicDao.selectCharacteristicsByIds(newHashSet(10), session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto().setId(10).setKey("REUSABILITY").setName("Reusability")));

    registry.reindex();

    Map<String, Object> ruleDocument =
        esSetup
            .client()
            .prepareGet("rules", "rule", Integer.toString(10))
            .execute()
            .actionGet()
            .getSourceAsMap();
    assertThat(ruleDocument.get(RuleDocument.FIELD_CHARACTERISTIC_ID)).isEqualTo(10);
    assertThat(ruleDocument.get(RuleDocument.FIELD_CHARACTERISTIC_KEY)).isEqualTo("REUSABILITY");
    assertThat(ruleDocument.get(RuleDocument.FIELD_SUB_CHARACTERISTIC_ID)).isEqualTo(11);
    assertThat(ruleDocument.get(RuleDocument.FIELD_SUB_CHARACTERISTIC_KEY)).isEqualTo("MODULARITY");

    assertThat(ruleDocument.get(RuleDocument.FIELD_REMEDIATION_FUNCTION)).isEqualTo("LINEAR");
    assertThat(ruleDocument.get(RuleDocument.FIELD_REMEDIATION_COEFFICIENT)).isEqualTo("1h");
    assertThat(ruleDocument.get(RuleDocument.FIELD_REMEDIATION_OFFSET)).isNull();
  }
  @Test
  public void do_nothing_when_move_down_and_already_on_bottom() {
    when(dao.selectById(10, session))
        .thenReturn(new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setOrder(2));
    when(dao.selectEnabledRootCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto().setId(2).setKey("PORTABILITY").setOrder(1),
                new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setOrder(2)));

    service.moveDown(10);

    verify(dao, never()).update(any(CharacteristicDto.class), eq(session));
  }
  @Test
  public void backup_with_disabled_rules() {
    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability updated")
                    .setOrder(2),
                new CharacteristicDto()
                    .setId(2)
                    .setKey("COMPILER")
                    .setName("Compiler updated")
                    .setParentId(1)));

    when(ruleDao.selectEnabledAndNonManual(session))
        .thenReturn(
            newArrayList(
                // Debt disabled
                new RuleDto()
                    .setRepositoryKey("squid")
                    .setRuleKey("UselessImportCheck")
                    .setSubCharacteristicId(RuleDto.DISABLED_CHARACTERISTIC_ID),

                // Not debt
                new RuleDto().setRepositoryKey("squid").setRuleKey("AvoidNPE")));

    debtModelBackup.backup();

    verify(debtModelXMLExporter).export(any(DebtModel.class), ruleDebtListCaptor.capture());

    assertThat(ruleDebtListCaptor.getValue()).isEmpty();
  }
  @Test
  public void
      restore_from_xml_disable_rule_debt_when_not_in_xml_and_rule_have_default_debt_values() {
    when(characteristicsXMLImporter.importXML(anyString()))
        .thenReturn(
            new DebtModel()
                .addRootCharacteristic(
                    new DefaultDebtCharacteristic()
                        .setKey("PORTABILITY")
                        .setName("Portability")
                        .setOrder(1))
                .addSubCharacteristic(
                    new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"),
                    "PORTABILITY"));

    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability")
                    .setOrder(1)
                    .setCreatedAt(oldDate),
                new CharacteristicDto()
                    .setId(2)
                    .setKey("COMPILER")
                    .setName("Compiler")
                    .setParentId(1)
                    .setCreatedAt(oldDate)));

    when(ruleDao.selectEnabledAndNonManual(session))
        .thenReturn(
            newArrayList(
                new RuleDto()
                    .setId(1)
                    .setRepositoryKey("squid")
                    .setRuleKey("UselessImportCheck")
                    .setDefaultSubCharacteristicId(2)
                    .setDefaultRemediationFunction("LINEAR_OFFSET")
                    .setDefaultRemediationCoefficient("2h")
                    .setDefaultRemediationOffset("15min")
                //        .setCreatedAt(oldDate).setUpdatedAt(oldDate)
                ));

    debtModelBackup.restoreFromXml("<xml/>");

    verify(ruleOperations)
        .updateRule(
            ruleCaptor.capture(),
            isNull(CharacteristicDto.class),
            isNull(String.class),
            isNull(String.class),
            isNull(String.class),
            eq(session));

    verify(ruleDao).selectEnabledAndNonManual(session);
    verify(session).commit();
  }
  @Test
  public void not_rename_characteristic_when_renaming_with_same_name() {
    when(dao.selectById(10, session)).thenReturn(subCharacteristicDto);

    service.rename(10, "Efficiency");

    verify(dao, never()).update(any(CharacteristicDto.class), eq(session));
  }
  @Test
  public void fail_to_move_sub_characteristic() {
    when(dao.selectById(10, session))
        .thenReturn(new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setParentId(1));
    when(dao.selectEnabledRootCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setOrder(2),
                new CharacteristicDto().setId(2).setKey("PORTABILITY").setOrder(3)));

    try {
      service.moveDown(10);
      fail();
    } catch (BadRequestException e) {
      assertThat(e.firstError().getKey()).isEqualTo("Sub characteristics can not be moved.");
    }
    verify(dao, never()).update(any(CharacteristicDto.class), eq(session));
  }
  @Test
  public void rename_characteristic() {
    when(dao.selectById(10, session)).thenReturn(subCharacteristicDto);

    DefaultDebtCharacteristic result =
        (DefaultDebtCharacteristic) service.rename(10, "New Efficiency");

    assertThat(result.key()).isEqualTo("EFFICIENCY");
    assertThat(result.name()).isEqualTo("New Efficiency");
    assertThat(result.updatedAt()).isEqualTo(now);
  }
  @Test
  public void move_down() {
    when(dao.selectById(10, session))
        .thenReturn(new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setOrder(2));
    when(dao.selectEnabledRootCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setOrder(2),
                new CharacteristicDto().setId(2).setKey("PORTABILITY").setOrder(3)));

    DebtCharacteristic result = service.moveDown(10);

    verify(dao, times(2)).update(characteristicCaptor.capture(), eq(session));

    assertThat(result.order()).isEqualTo(3);
    assertThat(characteristicCaptor.getAllValues().get(0).getOrder()).isEqualTo(2);
    assertThat(characteristicCaptor.getAllValues().get(0).getUpdatedAt()).isEqualTo(now);
    assertThat(characteristicCaptor.getAllValues().get(1).getOrder()).isEqualTo(3);
    assertThat(characteristicCaptor.getAllValues().get(1).getUpdatedAt()).isEqualTo(now);
  }
  @Test
  public void backup_from_language() {
    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability updated")
                    .setOrder(2),
                new CharacteristicDto()
                    .setId(2)
                    .setKey("COMPILER")
                    .setName("Compiler updated")
                    .setParentId(1)));

    when(ruleDao.selectEnabledAndNonManual(session))
        .thenReturn(
            newArrayList(
                new RuleDto()
                    .setId(1)
                    .setRepositoryKey("squid")
                    .setRuleKey("UselessImportCheck")
                    .setLanguage("java")
                    .setSubCharacteristicId(2)
                    .setRemediationFunction(DebtRemediationFunction.Type.CONSTANT_ISSUE.toString())
                    .setRemediationOffset("15min"),
                //        .setCreatedAt(oldDate).setUpdatedAt(oldDate),
                // Should be ignored
                new RuleDto()
                    .setId(2)
                    .setRepositoryKey("checkstyle")
                    .setLanguage("java2")
                    .setSubCharacteristicId(3)
                    .setRemediationFunction(DebtRemediationFunction.Type.LINEAR.toString())
                    .setRemediationCoefficient("2h")
                //        .setCreatedAt(oldDate).setUpdatedAt(oldDate)
                ));

    debtModelBackup.backup("java");

    verify(debtModelXMLExporter).export(any(DebtModel.class), ruleDebtListCaptor.capture());

    List<RuleDebt> rules = ruleDebtListCaptor.getValue();
    assertThat(rules).hasSize(1);

    RuleDebt rule = rules.get(0);
    assertThat(rule.ruleKey().repository()).isEqualTo("squid");
    assertThat(rule.ruleKey().rule()).isEqualTo("UselessImportCheck");
    assertThat(rule.subCharacteristicKey()).isEqualTo("COMPILER");
    assertThat(rule.function()).isEqualTo("CONSTANT_ISSUE");
    assertThat(rule.coefficient()).isNull();
    assertThat(rule.offset()).isEqualTo("15min");
  }
  @Test
  public void update_characteristics_when_restoring_characteristics() {
    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                // Order and name have changed
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability updated")
                    .setOrder(2)
                    .setCreatedAt(oldDate)
                    .setUpdatedAt(oldDate),
                new CharacteristicDto()
                    .setId(2)
                    .setKey("COMPILER")
                    .setName("Compiler updated")
                    .setParentId(1)
                    .setCreatedAt(oldDate)
                    .setUpdatedAt(oldDate)));

    debtModelBackup.restoreCharacteristics(
        new DebtModel()
            .addRootCharacteristic(
                new DefaultDebtCharacteristic()
                    .setKey("PORTABILITY")
                    .setName("Portability")
                    .setOrder(1))
            .addSubCharacteristic(
                new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"),
                "PORTABILITY"),
        now,
        session);

    verify(dao, times(2)).update(characteristicCaptor.capture(), eq(session));

    CharacteristicDto dto1 = characteristicCaptor.getAllValues().get(0);
    assertThat(dto1.getId()).isEqualTo(1);
    assertThat(dto1.getKey()).isEqualTo("PORTABILITY");
    assertThat(dto1.getName()).isEqualTo("Portability");
    assertThat(dto1.getParentId()).isNull();
    assertThat(dto1.getOrder()).isEqualTo(1);
    assertThat(dto1.getCreatedAt()).isEqualTo(oldDate);
    assertThat(dto1.getUpdatedAt()).isEqualTo(now);

    CharacteristicDto dto2 = characteristicCaptor.getAllValues().get(1);
    assertThat(dto2.getId()).isEqualTo(2);
    assertThat(dto2.getKey()).isEqualTo("COMPILER");
    assertThat(dto2.getName()).isEqualTo("Compiler");
    assertThat(dto2.getParentId()).isEqualTo(1);
    assertThat(dto2.getOrder()).isNull();
    assertThat(dto2.getCreatedAt()).isEqualTo(oldDate);
    assertThat(dto2.getUpdatedAt()).isEqualTo(now);
  }
  @Test
  public void fail_to_create_sub_characteristic_when_parent_id_is_not_a_root_characteristic() {
    when(dao.selectById(1, session)).thenReturn(subCharacteristicDto);

    try {
      service.create("Compilation", 1);
      fail();
    } catch (BadRequestException e) {
      assertThat(e.firstError().getKey())
          .isEqualTo("A sub characteristic can not have a sub characteristic as parent.");
    }
  }
  @Test
  public void fail_to_move_characteristic_with_no_order() {
    when(dao.selectById(10, session))
        .thenReturn(new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setOrder(null));
    when(dao.selectEnabledRootCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto().setId(10).setKey("MEMORY_EFFICIENCY").setOrder(2),
                new CharacteristicDto().setId(2).setKey("PORTABILITY").setOrder(3)));

    try {
      service.moveDown(10);
      fail();
    } catch (Exception e) {
      assertThat(e)
          .isInstanceOf(IllegalArgumentException.class)
          .hasMessage("The order of the characteristic 'MEMORY_EFFICIENCY' should not be null");
    }

    verify(dao, never()).update(any(CharacteristicDto.class), eq(session));
  }
  @Test
  public void create_sub_characteristic() {
    when(dao.selectById(1, session)).thenReturn(characteristicDto);

    DefaultDebtCharacteristic result =
        (DefaultDebtCharacteristic) service.create("Compilation name", 1);

    assertThat(result.id()).isEqualTo(currentId);
    assertThat(result.key()).isEqualTo("COMPILATION_NAME");
    assertThat(result.name()).isEqualTo("Compilation name");
    assertThat(result.parentId()).isEqualTo(1);
    assertThat(result.createdAt()).isEqualTo(now);
  }
  @Test
  public void create_first_characteristic() {
    when(dao.selectMaxCharacteristicOrder(session)).thenReturn(0);

    DefaultDebtCharacteristic result =
        (DefaultDebtCharacteristic) service.create("Portability", null);

    assertThat(result.id()).isEqualTo(currentId);
    assertThat(result.key()).isEqualTo("PORTABILITY");
    assertThat(result.name()).isEqualTo("Portability");
    assertThat(result.order()).isEqualTo(1);
    assertThat(result.createdAt()).isEqualTo(now);
  }
  @Test
  public void fail_to_create_sub_characteristic_when_parent_does_not_exists() {
    when(dao.selectById(1, session)).thenReturn(null);

    try {
      service.create("Compilation", 1);
      fail();
    } catch (Exception e) {
      assertThat(e)
          .isInstanceOf(NotFoundException.class)
          .hasMessage("Characteristic with id 1 does not exists.");
    }
  }
  @Test
  public void fail_to_rename_unknown_characteristic() {
    when(dao.selectById(10, session)).thenReturn(null);

    try {
      service.rename(10, "New Efficiency");
      fail();
    } catch (Exception e) {
      assertThat(e)
          .isInstanceOf(NotFoundException.class)
          .hasMessage("Characteristic with id 10 does not exists.");
    }
  }
  @Test
  public void backup_with_rule_having_default_linear_and_overridden_offset() {
    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability updated")
                    .setOrder(2),
                new CharacteristicDto()
                    .setId(2)
                    .setKey("COMPILER")
                    .setName("Compiler updated")
                    .setParentId(1)));

    when(ruleDao.selectEnabledAndNonManual(session))
        .thenReturn(
            newArrayList(
                // Rule with default debt values : default value is linear (only coefficient is set)
                // and overridden value is constant per issue (only offset is set)
                // -> Ony offset should be set
                new RuleDto()
                    .setRepositoryKey("squid")
                    .setRuleKey("AvoidNPE")
                    .setDefaultSubCharacteristicId(2)
                    .setDefaultRemediationFunction(DebtRemediationFunction.Type.LINEAR.toString())
                    .setDefaultRemediationCoefficient("2h")
                    .setSubCharacteristicId(2)
                    .setRemediationFunction(DebtRemediationFunction.Type.CONSTANT_ISSUE.toString())
                    .setRemediationOffset("15min")));

    debtModelBackup.backup();

    ArgumentCaptor<DebtModel> debtModelArgument = ArgumentCaptor.forClass(DebtModel.class);
    verify(debtModelXMLExporter).export(debtModelArgument.capture(), ruleDebtListCaptor.capture());
    assertThat(debtModelArgument.getValue().rootCharacteristics()).hasSize(1);
    assertThat(debtModelArgument.getValue().subCharacteristics("PORTABILITY")).hasSize(1);

    List<RuleDebt> rules = ruleDebtListCaptor.getValue();
    assertThat(rules).hasSize(1);

    RuleDebt rule = rules.get(0);
    assertThat(rule.ruleKey().repository()).isEqualTo("squid");
    assertThat(rule.ruleKey().rule()).isEqualTo("AvoidNPE");
    assertThat(rule.subCharacteristicKey()).isEqualTo("COMPILER");
    assertThat(rule.function()).isEqualTo("CONSTANT_ISSUE");
    assertThat(rule.offset()).isEqualTo("15min");
    assertThat(rule.coefficient()).isNull();
  }
  @Test
  public void disable_no_more_existing_characteristics_when_restoring_characteristics() {
    CharacteristicDto dto1 =
        new CharacteristicDto().setId(1).setKey("PORTABILITY").setName("Portability").setOrder(1);
    CharacteristicDto dto2 =
        new CharacteristicDto().setId(2).setKey("COMPILER").setName("Compiler").setParentId(1);

    when(dao.selectEnabledCharacteristics(session)).thenReturn(newArrayList(dto1, dto2));

    debtModelBackup.restoreCharacteristics(new DebtModel(), now, session);

    verify(debtModelOperations).delete(dto1, now, session);
    verify(debtModelOperations).delete(dto2, now, session);
  }
  @Test
  public void restore_from_xml_add_warning_message_when_rule_from_xml_is_not_found() {
    when(characteristicsXMLImporter.importXML(anyString()))
        .thenReturn(
            new DebtModel()
                .addRootCharacteristic(
                    new DefaultDebtCharacteristic()
                        .setKey("PORTABILITY")
                        .setName("Portability")
                        .setOrder(1))
                .addSubCharacteristic(
                    new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"),
                    "PORTABILITY"));

    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability")
                    .setOrder(1)
                    .setCreatedAt(oldDate),
                new CharacteristicDto()
                    .setId(2)
                    .setKey("COMPILER")
                    .setName("Compiler")
                    .setParentId(1)
                    .setCreatedAt(oldDate)));

    when(rulesXMLImporter.importXML(anyString(), any(ValidationMessages.class)))
        .thenReturn(
            newArrayList(
                new RuleDebt()
                    .setRuleKey(RuleKey.of("squid", "UselessImportCheck"))
                    .setSubCharacteristicKey("COMPILER")
                    .setFunction(DebtRemediationFunction.Type.LINEAR.name())
                    .setCoefficient("2h")));

    when(ruleDao.selectEnabledAndNonManual(session)).thenReturn(Collections.<RuleDto>emptyList());

    assertThat(debtModelBackup.restoreFromXml("<xml/>").getWarnings()).hasSize(1);

    verifyZeroInteractions(ruleOperations);

    verify(ruleDao).selectEnabledAndNonManual(session);
    verify(session).commit();
  }
  @Test
  public void delete_sub_characteristic() {
    DbSession batchSession = mock(DbSession.class);
    when(dbClient.openSession(true)).thenReturn(batchSession);

    when(ruleDao.findRulesByDebtSubCharacteristicId(batchSession, 2))
        .thenReturn(
            newArrayList(
                new RuleDto()
                    .setSubCharacteristicId(2)
                    .setRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.toString())
                    .setRemediationCoefficient("2h")
                    .setRemediationOffset("5min")
                    .setDefaultSubCharacteristicId(10)
                    .setDefaultRemediationFunction(
                        DebtRemediationFunction.Type.LINEAR_OFFSET.toString())
                    .setDefaultRemediationCoefficient("4h")
                    .setDefaultRemediationOffset("15min")));
    when(dao.selectById(2, batchSession)).thenReturn(subCharacteristicDto);

    service.delete(2);

    verify(ruleDao).update(eq(batchSession), ruleCaptor.capture());

    RuleDto ruleDto = ruleCaptor.getValue();
    assertThat(ruleDto.getUpdatedAt()).isEqualTo(now);

    // Overridden debt data are disabled
    assertThat(ruleDto.getSubCharacteristicId()).isEqualTo(-1);
    assertThat(ruleDto.getRemediationFunction()).isNull();
    assertThat(ruleDto.getRemediationCoefficient()).isNull();
    assertThat(ruleDto.getRemediationOffset()).isNull();

    // Default debt data should not be touched
    assertThat(ruleDto.getDefaultSubCharacteristicId()).isEqualTo(10);
    assertThat(ruleDto.getDefaultRemediationFunction()).isEqualTo("LINEAR_OFFSET");
    assertThat(ruleDto.getDefaultRemediationCoefficient()).isEqualTo("4h");
    assertThat(ruleDto.getDefaultRemediationOffset()).isEqualTo("15min");

    verify(dao).update(characteristicCaptor.capture(), eq(batchSession));
    CharacteristicDto characteristicDto = characteristicCaptor.getValue();

    // Sub characteristic is disable
    assertThat(characteristicDto.getId()).isEqualTo(2);
    assertThat(characteristicDto.isEnabled()).isFalse();
    assertThat(characteristicDto.getUpdatedAt()).isEqualTo(now);
  }
  @Test
  public void not_delete_already_disabled_characteristic() {
    DbSession batchSession = mock(DbSession.class);
    when(dbClient.openSession(true)).thenReturn(batchSession);

    when(dao.selectById(1, batchSession))
        .thenReturn(
            new CharacteristicDto()
                .setId(1)
                .setKey("MEMORY_EFFICIENCY")
                .setName("Memory use")
                .setOrder(2)
                .setEnabled(false));

    service.delete(1);

    verify(dao, never()).update(any(CharacteristicDto.class), eq(batchSession));
  }
  @Test
  public void reset_model_do_not_load_rule_definitions_if_no_rule() {
    when(characteristicsXMLImporter.importXML(any(Reader.class)))
        .thenReturn(
            new DebtModel()
                .addRootCharacteristic(
                    new DefaultDebtCharacteristic()
                        .setKey("PORTABILITY")
                        .setName("Portability")
                        .setOrder(1))
                .addSubCharacteristic(
                    new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"),
                    "PORTABILITY"));

    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability updated")
                    .setOrder(2)
                    .setCreatedAt(oldDate),
                new CharacteristicDto()
                    .setId(2)
                    .setKey("COMPILER")
                    .setName("Compiler updated")
                    .setParentId(1)
                    .setCreatedAt(oldDate)));

    when(ruleDao.selectEnabledAndNonManual(session)).thenReturn(Collections.<RuleDto>emptyList());

    debtModelBackup.reset();

    verify(dao).selectEnabledCharacteristics(session);
    verify(dao, times(2)).update(any(CharacteristicDto.class), eq(session));
    verifyNoMoreInteractions(dao);

    verify(ruleDao).selectEnabledAndNonManual(session);
    verify(ruleDao, never()).update(eq(session), any(RuleDto.class));
    verifyZeroInteractions(defLoader);

    verify(session).commit();
  }
  @Test
  public void create_characteristics_when_restoring_characteristics() {
    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(Collections.<CharacteristicDto>emptyList());

    debtModelBackup.restoreCharacteristics(
        new DebtModel()
            .addRootCharacteristic(
                new DefaultDebtCharacteristic()
                    .setKey("PORTABILITY")
                    .setName("Portability")
                    .setOrder(1))
            .addSubCharacteristic(
                new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"),
                "PORTABILITY"),
        now,
        session);

    verify(dao, times(2)).insert(characteristicCaptor.capture(), eq(session));

    CharacteristicDto dto1 = characteristicCaptor.getAllValues().get(0);
    assertThat(dto1.getId()).isEqualTo(10);
    assertThat(dto1.getKey()).isEqualTo("PORTABILITY");
    assertThat(dto1.getName()).isEqualTo("Portability");
    assertThat(dto1.getParentId()).isNull();
    assertThat(dto1.getOrder()).isEqualTo(1);
    assertThat(dto1.getCreatedAt()).isEqualTo(now);
    assertThat(dto1.getUpdatedAt()).isNull();

    CharacteristicDto dto2 = characteristicCaptor.getAllValues().get(1);
    assertThat(dto2.getId()).isEqualTo(11);
    assertThat(dto2.getKey()).isEqualTo("COMPILER");
    assertThat(dto2.getName()).isEqualTo("Compiler");
    assertThat(dto2.getParentId()).isEqualTo(10);
    assertThat(dto2.getOrder()).isNull();
    assertThat(dto2.getCreatedAt()).isEqualTo(now);
    assertThat(dto2.getUpdatedAt()).isNull();
  }
  @Test
  public void restore_from_xml_and_language_disable_no_more_existing_characteristics() {
    when(characteristicsXMLImporter.importXML(anyString()))
        .thenReturn(
            new DebtModel()
                .addRootCharacteristic(
                    new DefaultDebtCharacteristic()
                        .setKey("PORTABILITY")
                        .setName("Portability")
                        .setOrder(1)));

    CharacteristicDto dto1 =
        new CharacteristicDto().setId(1).setKey("PORTABILITY").setName("Portability").setOrder(1);
    // No more existing characteristic
    CharacteristicDto dto2 =
        new CharacteristicDto().setId(2).setKey("COMPILER").setName("Compiler").setParentId(1);
    when(dao.selectEnabledCharacteristics(session)).thenReturn(newArrayList(dto1, dto2));

    debtModelBackup.restoreFromXml("<xml/>", "java");

    verify(debtModelOperations).delete(dto2, now, session);
    verify(session).commit();
  }
  @Test
  public void reset_model_when_no_default_value() {
    when(characteristicsXMLImporter.importXML(any(Reader.class)))
        .thenReturn(
            new DebtModel()
                .addRootCharacteristic(
                    new DefaultDebtCharacteristic()
                        .setKey("PORTABILITY")
                        .setName("Portability")
                        .setOrder(1))
                .addSubCharacteristic(
                    new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"),
                    "PORTABILITY"));

    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability updated")
                    .setOrder(2)
                    .setCreatedAt(oldDate),
                new CharacteristicDto()
                    .setId(2)
                    .setKey("COMPILER")
                    .setName("Compiler updated")
                    .setParentId(1)
                    .setCreatedAt(oldDate)));

    when(ruleDao.selectEnabledAndNonManual(session))
        .thenReturn(
            newArrayList(
                new RuleDto()
                    .setRepositoryKey("squid")
                    .setRuleKey("NPE")
                    .setDefaultSubCharacteristicId(10)
                    .setDefaultRemediationFunction(DebtRemediationFunction.Type.LINEAR.toString())
                    .setDefaultRemediationCoefficient("2h")
                    .setSubCharacteristicId(2)
                    .setRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.toString())
                    .setRemediationCoefficient("2h")
                    .setRemediationOffset("15min")));

    RulesDefinition.Context context = new RulesDefinition.Context();
    RulesDefinition.NewRepository repo = context.createRepository("squid", "java").setName("Squid");
    repo.createRule("NPE")
        .setName("Detect NPE")
        .setHtmlDescription("Detect <code>java.lang.NullPointerException</code>")
        .setSeverity(Severity.BLOCKER)
        .setStatus(RuleStatus.BETA);
    repo.done();
    when(defLoader.load()).thenReturn(context);

    debtModelBackup.reset();

    verify(dao).selectEnabledCharacteristics(session);
    verify(dao, times(2)).update(any(CharacteristicDto.class), eq(session));
    verifyNoMoreInteractions(dao);

    verify(ruleDao).selectEnabledAndNonManual(session);
    verify(ruleDao).update(eq(session), ruleCaptor.capture());
    verifyNoMoreInteractions(ruleDao);

    verify(session).commit();

    RuleDto rule = ruleCaptor.getValue();
    assertThat(rule.getDefaultSubCharacteristicId()).isNull();
    assertThat(rule.getDefaultRemediationFunction()).isNull();
    assertThat(rule.getDefaultRemediationCoefficient()).isNull();
    assertThat(rule.getDefaultRemediationOffset()).isNull();
    assertThat(rule.getUpdatedAt()).isEqualTo(now);
  }
  @Test
  public void reset_model_on_custom_rules() {
    when(characteristicsXMLImporter.importXML(any(Reader.class)))
        .thenReturn(
            new DebtModel()
                .addRootCharacteristic(
                    new DefaultDebtCharacteristic()
                        .setKey("PORTABILITY")
                        .setName("Portability")
                        .setOrder(1))
                .addSubCharacteristic(
                    new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"),
                    "PORTABILITY"));

    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability updated")
                    .setOrder(2)
                    .setCreatedAt(oldDate),
                new CharacteristicDto()
                    .setId(2)
                    .setKey("COMPILER")
                    .setName("Compiler updated")
                    .setParentId(1)
                    .setCreatedAt(oldDate)));

    when(ruleDao.selectEnabledAndNonManual(session))
        .thenReturn(
            newArrayList(
                // Template rule
                new RuleDto()
                    .setId(5)
                    .setRepositoryKey("squid")
                    .setRuleKey("XPath")
                    .setSubCharacteristicId(2)
                    .setRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.toString())
                    .setRemediationCoefficient("2h")
                    .setRemediationOffset("15min"),
                // Custom rule
                new RuleDto()
                    .setId(6)
                    .setRepositoryKey("squid")
                    .setRuleKey("XPath_1369910135")
                    .setTemplateId(5)
                    .setSubCharacteristicId(2)
                    .setRemediationFunction(DebtRemediationFunction.Type.LINEAR_OFFSET.toString())
                    .setRemediationCoefficient("2h")
                    .setRemediationOffset("15min")));

    RulesDefinition.Context context = new RulesDefinition.Context();
    // Template rule
    RulesDefinition.NewRepository repo = context.createRepository("squid", "java").setName("XPath");
    RulesDefinition.NewRule newRule =
        repo.createRule("XPath")
            .setName("XPath")
            .setHtmlDescription("XPath")
            .setSeverity(Severity.BLOCKER)
            .setStatus(RuleStatus.BETA)
            .setDebtSubCharacteristic("COMPILER");
    newRule.setDebtRemediationFunction(
        newRule.debtRemediationFunctions().linearWithOffset("4h", "20min"));
    repo.done();
    when(defLoader.load()).thenReturn(context);

    debtModelBackup.reset();

    verify(ruleDao).selectEnabledAndNonManual(session);
    verify(ruleDao, times(2)).update(eq(session), ruleCaptor.capture());
    verifyNoMoreInteractions(ruleDao);
    verify(session).commit();

    RuleDto rule = ruleCaptor.getAllValues().get(1);

    assertThat(rule.getId()).isEqualTo(6);
    assertThat(rule.getDefaultSubCharacteristicId()).isEqualTo(2);
    assertThat(rule.getDefaultRemediationFunction()).isEqualTo("LINEAR_OFFSET");
    assertThat(rule.getDefaultRemediationCoefficient()).isEqualTo("4h");
    assertThat(rule.getDefaultRemediationOffset()).isEqualTo("20min");
    assertThat(rule.getUpdatedAt()).isEqualTo(now);

    assertThat(rule.getSubCharacteristicId()).isNull();
    assertThat(rule.getRemediationFunction()).isNull();
    assertThat(rule.getRemediationCoefficient()).isNull();
    assertThat(rule.getRemediationOffset()).isNull();
    assertThat(rule.getUpdatedAt()).isEqualTo(now);
  }
  @Test
  public void restore_from_xml_and_language() {
    when(characteristicsXMLImporter.importXML(anyString()))
        .thenReturn(
            new DebtModel()
                .addRootCharacteristic(
                    new DefaultDebtCharacteristic()
                        .setKey("PORTABILITY")
                        .setName("Portability")
                        .setOrder(1))
                .addSubCharacteristic(
                    new DefaultDebtCharacteristic().setKey("COMPILER").setName("Compiler"),
                    "PORTABILITY"));

    CharacteristicDto compiler =
        new CharacteristicDto()
            .setId(2)
            .setKey("COMPILER")
            .setName("Compiler")
            .setParentId(1)
            .setCreatedAt(oldDate);
    when(dao.selectEnabledCharacteristics(session))
        .thenReturn(
            newArrayList(
                new CharacteristicDto()
                    .setId(1)
                    .setKey("PORTABILITY")
                    .setName("Portability")
                    .setOrder(1)
                    .setCreatedAt(oldDate),
                compiler));

    when(rulesXMLImporter.importXML(anyString(), any(ValidationMessages.class)))
        .thenReturn(
            newArrayList(
                new RuleDebt()
                    .setRuleKey(RuleKey.of("squid", "UselessImportCheck"))
                    .setSubCharacteristicKey("COMPILER")
                    .setFunction(DebtRemediationFunction.Type.LINEAR.name())
                    .setCoefficient("2h")));

    when(ruleDao.selectEnabledAndNonManual(session))
        .thenReturn(
            newArrayList(
                new RuleDto()
                    .setId(1)
                    .setRepositoryKey("squid")
                    .setRuleKey("UselessImportCheck")
                    .setLanguage("java")
                    .setDefaultSubCharacteristicId(10)
                    .setDefaultRemediationFunction(DebtRemediationFunction.Type.LINEAR.toString())
                    .setDefaultRemediationCoefficient("2h"),
                // Should be ignored
                new RuleDto()
                    .setId(2)
                    .setRepositoryKey("checkstyle")
                    .setLanguage("java2")
                    .setSubCharacteristicId(3)
                    .setRemediationFunction(DebtRemediationFunction.Type.LINEAR.toString())
                    .setRemediationCoefficient("2h")));

    debtModelBackup.restoreFromXml("<xml/>", "java");

    verify(ruleOperations)
        .updateRule(
            ruleCaptor.capture(),
            eq(compiler),
            eq("LINEAR"),
            eq("2h"),
            isNull(String.class),
            eq(session));

    verify(ruleDao).selectEnabledAndNonManual(session);
    verify(session).commit();
  }
  @Test
  public void index_one_rule() {
    RuleDto ruleDto =
        new RuleDto()
            .setId(3)
            .setRepositoryKey("repo")
            .setRuleKey("key")
            .setSeverity(Severity.MINOR)
            .setNoteData("noteData")
            .setNoteUserLogin("userLogin")
            .setDefaultSubCharacteristicId(11)
            .setDefaultRemediationFunction("LINEAR_OFFSET")
            .setDefaultRemediationCoefficient("1h")
            .setDefaultRemediationOffset("15min");

    when(ruleDao.selectParametersByRuleIds(newArrayList(3), session))
        .thenReturn(newArrayList(new RuleParamDto().setRuleId(3).setName("name")));

    when(ruleDao.selectTagsByRuleIds(newArrayList(3), session))
        .thenReturn(
            newArrayList(
                new RuleRuleTagDto().setRuleId(3).setTag("tag1").setType(RuleTagType.SYSTEM),
                new RuleRuleTagDto().setRuleId(3).setTag("tag2").setType(RuleTagType.SYSTEM),
                new RuleRuleTagDto().setRuleId(3).setTag("tag").setType(RuleTagType.ADMIN)));

    when(characteristicDao.selectById(11, session))
        .thenReturn(
            new CharacteristicDto()
                .setId(11)
                .setKey("MODULARITY")
                .setName("Modularity")
                .setParentId(10));
    when(characteristicDao.selectById(10, session))
        .thenReturn(new CharacteristicDto().setId(10).setKey("REUSABILITY").setName("Reusability"));

    registry.reindex(ruleDto);

    Map<String, Object> ruleDocument =
        esSetup
            .client()
            .prepareGet("rules", "rule", Integer.toString(3))
            .execute()
            .actionGet()
            .getSourceAsMap();
    assertThat(ruleDocument.get(RuleDocument.FIELD_ID)).isEqualTo(3);
    assertThat(ruleDocument.get(RuleDocument.FIELD_REPOSITORY_KEY)).isEqualTo("repo");
    assertThat(ruleDocument.get(RuleDocument.FIELD_KEY)).isEqualTo("key");
    assertThat(ruleDocument.get(RuleDocument.FIELD_SEVERITY)).isEqualTo("MINOR");
    assertThat(ruleDocument.get(RuleDocument.FIELD_NOTE)).isNotNull();

    assertThat((List<String>) ruleDocument.get(RuleDocument.FIELD_PARAMS)).hasSize(1);
    assertThat((List<String>) ruleDocument.get(RuleDocument.FIELD_SYSTEM_TAGS)).hasSize(2);
    assertThat((List<String>) ruleDocument.get(RuleDocument.FIELD_ADMIN_TAGS)).hasSize(1);

    assertThat(ruleDocument.get(RuleDocument.FIELD_CHARACTERISTIC_ID)).isEqualTo(10);
    assertThat(ruleDocument.get(RuleDocument.FIELD_CHARACTERISTIC_KEY)).isEqualTo("REUSABILITY");
    assertThat(ruleDocument.get(RuleDocument.FIELD_SUB_CHARACTERISTIC_ID)).isEqualTo(11);
    assertThat(ruleDocument.get(RuleDocument.FIELD_SUB_CHARACTERISTIC_KEY)).isEqualTo("MODULARITY");
    assertThat(ruleDocument.get(RuleDocument.FIELD_REMEDIATION_FUNCTION))
        .isEqualTo("LINEAR_OFFSET");
    assertThat(ruleDocument.get(RuleDocument.FIELD_REMEDIATION_COEFFICIENT)).isEqualTo("1h");
    assertThat(ruleDocument.get(RuleDocument.FIELD_REMEDIATION_OFFSET)).isEqualTo("15min");
  }