@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 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 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 override_debt_only_offset() {
    insertDebtCharacteristics(dbSession);
    ruleDao.insert(
        dbSession,
        RuleTesting.newDto(RULE_KEY)
            .setDefaultSubCharacteristicId(hardReliabilityId)
            .setDefaultRemediationFunction(DebtRemediationFunction.Type.LINEAR.name())
            .setDefaultRemediationCoefficient("1d")
            .setDefaultRemediationOffset(null)
            .setRemediationFunction(null)
            .setRemediationCoefficient(null)
            .setRemediationOffset(null));
    dbSession.commit();

    RuleUpdate update =
        RuleUpdate.createForPluginRule(RULE_KEY)
            .setDebtRemediationFunction(
                new DefaultDebtRemediationFunction(
                    DebtRemediationFunction.Type.LINEAR, "2d", null));
    updater.update(update, userSessionRule);
    dbSession.clearCache();

    // verify debt is overridden
    Rule indexedRule = tester.get(RuleIndex.class).getByKey(RULE_KEY);
    assertThat(indexedRule.debtCharacteristicKey()).isEqualTo("RELIABILITY");
    assertThat(indexedRule.debtSubCharacteristicKey()).isEqualTo("HARD_RELIABILITY");
    assertThat(indexedRule.debtRemediationFunction().type())
        .isEqualTo(DebtRemediationFunction.Type.LINEAR);
    assertThat(indexedRule.debtRemediationFunction().coefficient()).isEqualTo("2d");
    assertThat(indexedRule.debtRemediationFunction().offset()).isNull();

    assertThat(indexedRule.debtOverloaded()).isTrue();
    assertThat(indexedRule.defaultDebtCharacteristicKey()).isEqualTo("RELIABILITY");
    assertThat(indexedRule.defaultDebtSubCharacteristicKey()).isEqualTo("HARD_RELIABILITY");
    assertThat(indexedRule.defaultDebtRemediationFunction().type())
        .isEqualTo(DebtRemediationFunction.Type.LINEAR);
    assertThat(indexedRule.defaultDebtRemediationFunction().coefficient()).isEqualTo("1d");
    assertThat(indexedRule.defaultDebtRemediationFunction().offset()).isNull();
  }
  @Test
  public void unset_debt() {
    insertDebtCharacteristics(dbSession);
    ruleDao.insert(
        dbSession,
        RuleTesting.newDto(RULE_KEY)
            .setDefaultSubCharacteristicId(hardReliabilityId)
            .setDefaultRemediationFunction(DebtRemediationFunction.Type.LINEAR.name())
            .setDefaultRemediationCoefficient("1d")
            .setDefaultRemediationOffset("5min")
            .setSubCharacteristicId(softReliabilityId)
            .setRemediationFunction(DebtRemediationFunction.Type.CONSTANT_ISSUE.name())
            .setRemediationCoefficient(null)
            .setRemediationOffset("1min"));
    dbSession.commit();

    RuleUpdate update = RuleUpdate.createForPluginRule(RULE_KEY).setDebtSubCharacteristic(null);
    updater.update(update, userSessionRule);

    // verify db
    dbSession.clearCache();
    RuleDto rule = ruleDao.getNullableByKey(dbSession, RULE_KEY);
    assertThat(rule.getSubCharacteristicId()).isEqualTo(-1);
    assertThat(rule.getRemediationFunction()).isNull();
    assertThat(rule.getRemediationCoefficient()).isNull();
    assertThat(rule.getRemediationOffset()).isNull();

    assertThat(rule.getDefaultSubCharacteristicId()).isNotNull();
    assertThat(rule.getDefaultRemediationFunction()).isNotNull();
    assertThat(rule.getDefaultRemediationCoefficient()).isNotNull();
    assertThat(rule.getDefaultRemediationOffset()).isNotNull();

    // verify index
    Rule indexedRule = tester.get(RuleIndex.class).getByKey(RULE_KEY);
    assertThat(indexedRule.debtCharacteristicKey()).isEqualTo("NONE");
    assertThat(indexedRule.debtSubCharacteristicKey()).isEqualTo("NONE");
    assertThat(indexedRule.debtRemediationFunction()).isNull();
    assertThat(indexedRule.debtOverloaded()).isTrue();
  }
  @Test
  public void reset_debt() {
    insertDebtCharacteristics(dbSession);
    ruleDao.insert(
        dbSession,
        RuleTesting.newDto(RULE_KEY)
            .setDefaultSubCharacteristicId(hardReliabilityId)
            .setDefaultRemediationFunction(DebtRemediationFunction.Type.LINEAR.name())
            .setDefaultRemediationCoefficient("1d")
            .setDefaultRemediationOffset("5min")
            .setSubCharacteristicId(softReliabilityId)
            .setRemediationFunction(DebtRemediationFunction.Type.CONSTANT_ISSUE.name())
            .setRemediationCoefficient(null)
            .setRemediationOffset("1min"));
    dbSession.commit();

    RuleUpdate update =
        RuleUpdate.createForPluginRule(RULE_KEY)
            .setDebtSubCharacteristic(RuleUpdate.DEFAULT_DEBT_CHARACTERISTIC);
    updater.update(update, userSessionRule);
    dbSession.clearCache();

    // verify debt is coming from default values
    Rule indexedRule = tester.get(RuleIndex.class).getByKey(RULE_KEY);
    assertThat(indexedRule.debtCharacteristicKey()).isEqualTo("RELIABILITY");
    assertThat(indexedRule.debtSubCharacteristicKey()).isEqualTo("HARD_RELIABILITY");
    assertThat(indexedRule.debtRemediationFunction().type())
        .isEqualTo(DebtRemediationFunction.Type.LINEAR);
    assertThat(indexedRule.debtRemediationFunction().coefficient()).isEqualTo("1d");
    assertThat(indexedRule.debtRemediationFunction().offset()).isEqualTo("5min");

    assertThat(indexedRule.debtOverloaded()).isFalse();
    assertThat(indexedRule.defaultDebtCharacteristicKey()).isEqualTo("RELIABILITY");
    assertThat(indexedRule.defaultDebtSubCharacteristicKey()).isEqualTo("HARD_RELIABILITY");
    assertThat(indexedRule.defaultDebtRemediationFunction().type())
        .isEqualTo(DebtRemediationFunction.Type.LINEAR);
    assertThat(indexedRule.defaultDebtRemediationFunction().coefficient()).isEqualTo("1d");
    assertThat(indexedRule.defaultDebtRemediationFunction().offset()).isEqualTo("5min");
  }
  @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 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 restore_from_xml_add_error_message_when_illegal_argument_exception() {
    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(
            newArrayList(
                new RuleDto()
                    .setId(1)
                    .setRepositoryKey("squid")
                    .setRuleKey("UselessImportCheck")
                    .setDefaultSubCharacteristicId(3)
                    .setDefaultRemediationFunction("LINEAR")
                    .setDefaultRemediationCoefficient("2h")
                //        .setCreatedAt(oldDate).setUpdatedAt(oldDate)
                ));

    when(ruleOperations.updateRule(
            any(RuleDto.class),
            any(CharacteristicDto.class),
            anyString(),
            anyString(),
            anyString(),
            eq(session)))
        .thenThrow(IllegalArgumentException.class);

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

    verify(ruleDao).selectEnabledAndNonManual(session);
    verify(session, never()).commit();
  }