if (debt != null) {
Rule rule = rules.find(ruleKey);
if (rule != null) {
- String characteristicKey = rule.debtCharacteristic();
+ String characteristicKey = rule.debtSubCharacteristic();
if (characteristicKey != null) {
Characteristic characteristic = model.characteristicByKey(characteristicKey);
if (characteristic != null) {
public void before() throws Exception {
when(perspectives.as(Issuable.class, resource)).thenReturn(issuable);
RulesBuilder rulesBuilder = new RulesBuilder();
- rulesBuilder.add(ruleKey1).setName("rule1").setDebtCharacteristic("MEMORY_EFFICIENCY");
- rulesBuilder.add(ruleKey2).setName("rule2").setDebtCharacteristic("MODULARITY");
+ rulesBuilder.add(ruleKey1).setName("rule1").setDebtSubCharacteristic("MEMORY_EFFICIENCY");
+ rulesBuilder.add(ruleKey2).setName("rule2").setDebtSubCharacteristic("MODULARITY");
rules = rulesBuilder.build();
when(ruleFinder.findByKey(ruleKey1)).thenReturn(org.sonar.api.rules.Rule.create(ruleKey1.repository(), ruleKey1.rule()));
package org.sonar.batch.debt;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
import org.picocontainer.injectors.ProviderAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.sonar.api.technicaldebt.batch.TechnicalDebtModel;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
+import org.sonar.api.batch.debt.DebtCharacteristic;
+import org.sonar.api.batch.debt.DebtModel;
+import org.sonar.api.batch.debt.internal.DefaultDebtCharacteristic;
+import org.sonar.api.batch.debt.internal.DefaultDebtModel;
import org.sonar.api.utils.TimeProfiler;
-import org.sonar.core.technicaldebt.DefaultTechnicalDebtModel;
import org.sonar.core.technicaldebt.db.CharacteristicDao;
import org.sonar.core.technicaldebt.db.CharacteristicDto;
-import java.util.List;
-import java.util.Map;
+import javax.annotation.Nullable;
-import static com.google.common.collect.Maps.newHashMap;
+import java.util.List;
public class DebtModelProvider extends ProviderAdapter {
private static final Logger LOG = LoggerFactory.getLogger(DebtModelProvider.class);
- private TechnicalDebtModel model;
+ private DebtModel model;
- public TechnicalDebtModel provide(CharacteristicDao dao) {
+ public DebtModel provide(CharacteristicDao dao) {
if (model == null) {
TimeProfiler profiler = new TimeProfiler(LOG).start("Loading technical debt model");
model = load(dao);
return model;
}
- private TechnicalDebtModel load(CharacteristicDao dao) {
- DefaultTechnicalDebtModel debtModel = new DefaultTechnicalDebtModel();
- List<CharacteristicDto> dtos = dao.selectEnabledCharacteristics();
- Map<Integer, DefaultCharacteristic> characteristicsById = newHashMap();
+ private DebtModel load(CharacteristicDao dao) {
+ DefaultDebtModel debtModel = new DefaultDebtModel();
- addRootCharacteristics(debtModel, dtos, characteristicsById);
- addCharacteristics(dtos, characteristicsById);
+ List<CharacteristicDto> allCharacteristics = dao.selectEnabledCharacteristics();
+ for (CharacteristicDto dto : allCharacteristics) {
+ Integer parentId = dto.getParentId();
+ if (parentId == null) {
+ debtModel.addCharacteristic(toDebtCharacteristic(dto));
+ } else {
+ debtModel.addSubCharacteristic(toDebtCharacteristic(dto), characteristicById(parentId, allCharacteristics).getKey());
+ }
+ }
return debtModel;
}
- private void addRootCharacteristics(DefaultTechnicalDebtModel model, List<CharacteristicDto> dtos, Map<Integer, DefaultCharacteristic> characteristicsById) {
- for (CharacteristicDto dto : dtos) {
- if (dto.getParentId() == null) {
- DefaultCharacteristic rootCharacteristic = dto.toCharacteristic(null);
- model.addRootCharacteristic(rootCharacteristic);
- characteristicsById.put(dto.getId(), rootCharacteristic);
+ private static CharacteristicDto characteristicById(final int id, List<CharacteristicDto> allCharacteristics) {
+ return Iterables.find(allCharacteristics, new Predicate<CharacteristicDto>() {
+ @Override
+ public boolean apply(@Nullable CharacteristicDto input) {
+ return input != null && id == input.getId();
}
- }
+ });
}
- private void addCharacteristics(List<CharacteristicDto> dtos, Map<Integer, DefaultCharacteristic> characteristicsById) {
- for (CharacteristicDto dto : dtos) {
- if (dto.getParentId() != null) {
- DefaultCharacteristic parent = characteristicsById.get(dto.getParentId());
- DefaultCharacteristic characteristic = dto.toCharacteristic(parent);
- characteristicsById.put(dto.getId(), characteristic);
- }
- }
+ private static DebtCharacteristic toDebtCharacteristic(CharacteristicDto characteristic) {
+ return new DefaultDebtCharacteristic()
+ .setId(characteristic.getId())
+ .setKey(characteristic.getKey())
+ .setName(characteristic.getName())
+ .setOrder(characteristic.getOrder())
+ .setParentId(characteristic.getParentId());
}
+
}
issue.setSeverity(activeRule.severity());
}
DebtRemediationFunction function = rule.debtRemediationFunction();
- if (rule.debtCharacteristic() != null && function != null) {
+ if (rule.debtSubCharacteristic() != null && function != null) {
issue.setDebt(calculateDebt(function, issue.effortToFix(), rule.key()));
}
}
import org.picocontainer.injectors.ProviderAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.sonar.api.batch.debt.DebtCharacteristic;
+import org.sonar.api.batch.debt.DebtModel;
+import org.sonar.api.batch.debt.internal.DefaultDebtModel;
import org.sonar.api.batch.rule.DebtRemediationFunction;
import org.sonar.api.batch.rule.Rules;
import org.sonar.api.batch.rule.internal.NewRule;
import org.sonar.api.batch.rule.internal.RulesBuilder;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
-import org.sonar.api.technicaldebt.batch.Characteristic;
-import org.sonar.api.technicaldebt.batch.TechnicalDebtModel;
import org.sonar.api.utils.Durations;
import org.sonar.api.utils.TimeProfiler;
import org.sonar.core.rule.RuleDao;
private Rules singleton = null;
- public Rules provide(RuleDao ruleDao, TechnicalDebtModel debtModel, Durations durations) {
+ public Rules provide(RuleDao ruleDao, DebtModel debtModel, Durations durations) {
if (singleton == null) {
TimeProfiler profiler = new TimeProfiler(LOG).start("Loading rules");
- singleton = load(ruleDao, debtModel, durations);
+ singleton = load(ruleDao, (DefaultDebtModel) debtModel, durations);
profiler.stop();
}
return singleton;
}
- private Rules load(RuleDao ruleDao, TechnicalDebtModel debtModel, Durations durations) {
+ private Rules load(RuleDao ruleDao, DefaultDebtModel debtModel, Durations durations) {
RulesBuilder rulesBuilder = new RulesBuilder();
List<RuleParamDto> ruleParamDtos = ruleDao.selectParameters();
// TODO should we set metadata ?
if (hasCharacteristic(ruleDto)) {
- newRule.setDebtCharacteristic(effectiveCharacteristic(ruleDto, ruleKey, debtModel).key());
+ newRule.setDebtSubCharacteristic(effectiveCharacteristic(ruleDto, ruleKey, debtModel).key());
newRule.setDebtRemediationFunction(effectiveFunction(ruleDto, ruleKey, durations));
}
return rulesBuilder.build();
}
- private Characteristic effectiveCharacteristic(RuleDto ruleDto, RuleKey ruleKey, TechnicalDebtModel debtModel) {
+ private DebtCharacteristic effectiveCharacteristic(RuleDto ruleDto, RuleKey ruleKey, DefaultDebtModel debtModel) {
Integer subCharacteristicId = ruleDto.getSubCharacteristicId();
Integer defaultSubCharacteristicId = ruleDto.getDefaultSubCharacteristicId();
Integer effectiveSubCharacteristicId = subCharacteristicId != null ? subCharacteristicId : defaultSubCharacteristicId;
- Characteristic subCharacteristic = debtModel.characteristicById(effectiveSubCharacteristicId);
+ DebtCharacteristic subCharacteristic = debtModel.characteristicById(effectiveSubCharacteristicId);
if (subCharacteristic == null) {
throw new IllegalStateException(String.format("Sub characteristic id '%s' on rule '%s' has not been found", effectiveSubCharacteristicId, ruleKey));
}
import org.sonar.batch.DefaultResourceCreationLock;
import org.sonar.batch.ProjectConfigurator;
import org.sonar.batch.ProjectTree;
-import org.sonar.batch.bootstrap.BootstrapSettings;
-import org.sonar.batch.bootstrap.ExtensionInstaller;
-import org.sonar.batch.bootstrap.ExtensionMatcher;
-import org.sonar.batch.bootstrap.ExtensionUtils;
-import org.sonar.batch.bootstrap.MetricProvider;
+import org.sonar.batch.bootstrap.*;
import org.sonar.batch.components.PeriodsDefinition;
import org.sonar.batch.debt.DebtModelProvider;
import org.sonar.batch.debt.IssueChangelogDebtCalculator;
-import org.sonar.batch.index.Caches;
-import org.sonar.batch.index.ComponentDataCache;
-import org.sonar.batch.index.ComponentDataPersister;
-import org.sonar.batch.index.DefaultIndex;
-import org.sonar.batch.index.DefaultPersistenceManager;
-import org.sonar.batch.index.DefaultResourcePersister;
-import org.sonar.batch.index.DependencyPersister;
-import org.sonar.batch.index.EventPersister;
-import org.sonar.batch.index.LinkPersister;
-import org.sonar.batch.index.MeasurePersister;
-import org.sonar.batch.index.MemoryOptimizer;
-import org.sonar.batch.index.ResourceCache;
-import org.sonar.batch.index.ResourceKeyMigration;
-import org.sonar.batch.index.SnapshotCache;
-import org.sonar.batch.index.SourcePersister;
-import org.sonar.batch.issue.DefaultProjectIssues;
-import org.sonar.batch.issue.DeprecatedViolations;
-import org.sonar.batch.issue.IssueCache;
-import org.sonar.batch.issue.IssuePersister;
-import org.sonar.batch.issue.ScanIssueStorage;
+import org.sonar.batch.index.*;
+import org.sonar.batch.issue.*;
import org.sonar.batch.phases.GraphPersister;
import org.sonar.batch.profiling.PhasesSumUpTimeProfiler;
import org.sonar.batch.rule.RulesProvider;
import org.sonar.core.issue.workflow.FunctionExecutor;
import org.sonar.core.issue.workflow.IssueWorkflow;
import org.sonar.core.notification.DefaultNotificationManager;
+import org.sonar.core.technicaldebt.DefaultTechnicalDebtModel;
import org.sonar.core.test.TestPlanBuilder;
import org.sonar.core.test.TestPlanPerspectiveLoader;
import org.sonar.core.test.TestableBuilder;
SymbolizableBuilder.class,
// technical debt
+ DefaultTechnicalDebtModel.class,
new DebtModelProvider(),
// rules
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
-import org.sonar.core.technicaldebt.DefaultTechnicalDebtModel;
+import org.sonar.api.batch.debt.DebtCharacteristic;
+import org.sonar.api.batch.debt.DebtModel;
import org.sonar.core.technicaldebt.db.CharacteristicDao;
import org.sonar.core.technicaldebt.db.CharacteristicDto;
DebtModelProvider provider;
-
@Before
public void before() {
provider = new DebtModelProvider();
}
@Test
- public void find_all() throws Exception {
+ public void provide_model() throws Exception {
CharacteristicDto rootCharacteristicDto = new CharacteristicDto()
.setId(1)
.setKey("MEMORY_EFFICIENCY")
- .setName("Memory use");
+ .setName("Memory use")
+ .setOrder(1);
CharacteristicDto characteristicDto = new CharacteristicDto()
.setId(2)
when(dao.selectEnabledCharacteristics()).thenReturn(newArrayList(rootCharacteristicDto, characteristicDto));
- DefaultTechnicalDebtModel result = (DefaultTechnicalDebtModel) provider.provide(dao);
- assertThat(result.rootCharacteristics()).hasSize(1);
+ DebtModel result = provider.provide(dao);
+ assertThat(result.characteristics()).hasSize(1);
- DefaultCharacteristic rootCharacteristic = result.characteristicByKey("MEMORY_EFFICIENCY");
- assertThat(rootCharacteristic.key()).isEqualTo("MEMORY_EFFICIENCY");
- assertThat(rootCharacteristic.name()).isEqualTo("Memory use");
- assertThat(rootCharacteristic.parent()).isNull();
- assertThat(rootCharacteristic.children()).hasSize(1);
- assertThat(rootCharacteristic.children().get(0).key()).isEqualTo("EFFICIENCY");
+ DebtCharacteristic characteristic = result.characteristicByKey("MEMORY_EFFICIENCY");
+ assertThat(characteristic.key()).isEqualTo("MEMORY_EFFICIENCY");
+ assertThat(characteristic.name()).isEqualTo("Memory use");
+ assertThat(characteristic.isSub()).isFalse();
+ assertThat(characteristic.order()).isEqualTo(1);
- DefaultCharacteristic characteristic = result.characteristicByKey("EFFICIENCY");
- assertThat(characteristic.key()).isEqualTo("EFFICIENCY");
- assertThat(characteristic.name()).isEqualTo("Efficiency");
- assertThat(characteristic.parent().key()).isEqualTo("MEMORY_EFFICIENCY");
- assertThat(characteristic.children()).isEmpty();
+ DebtCharacteristic subCharacteristic = result.characteristicByKey("EFFICIENCY");
+ assertThat(subCharacteristic.key()).isEqualTo("EFFICIENCY");
+ assertThat(subCharacteristic.name()).isEqualTo("Efficiency");
+ assertThat(subCharacteristic.isSub()).isTrue();
+ assertThat(subCharacteristic.order()).isNull();
}
-
}
import static org.fest.assertions.Fail.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
@RunWith(MockitoJUnitRunner.class)
public class ModuleIssuesTest {
public void set_debt_with_linear_function() throws Exception {
ruleBuilder.add(SQUID_RULE_KEY)
.setName(SQUID_RULE_NAME)
- .setDebtCharacteristic("COMPILER_RELATED_PORTABILITY")
+ .setDebtSubCharacteristic("COMPILER_RELATED_PORTABILITY")
.setDebtRemediationFunction(DebtRemediationFunction.createLinear(Duration.create(10L)));
activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO);
initModuleIssues();
public void set_debt_with_linear_with_offset_function() throws Exception {
ruleBuilder.add(SQUID_RULE_KEY)
.setName(SQUID_RULE_NAME)
- .setDebtCharacteristic("COMPILER_RELATED_PORTABILITY")
+ .setDebtSubCharacteristic("COMPILER_RELATED_PORTABILITY")
.setDebtRemediationFunction(DebtRemediationFunction.createLinearWithOffset(Duration.create(10L), Duration.create(25L)));
activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO);
initModuleIssues();
public void set_debt_with_constant_issue_function() throws Exception {
ruleBuilder.add(SQUID_RULE_KEY)
.setName(SQUID_RULE_NAME)
- .setDebtCharacteristic("COMPILER_RELATED_PORTABILITY")
+ .setDebtSubCharacteristic("COMPILER_RELATED_PORTABILITY")
.setDebtRemediationFunction(DebtRemediationFunction.createConstantPerIssue(Duration.create(10L)));
activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO);
initModuleIssues();
public void fail_to_set_debt_with_constant_issue_function_when_effort_to_fix_is_set() throws Exception {
ruleBuilder.add(SQUID_RULE_KEY)
.setName(SQUID_RULE_NAME)
- .setDebtCharacteristic("COMPILER_RELATED_PORTABILITY")
+ .setDebtSubCharacteristic("COMPILER_RELATED_PORTABILITY")
.setDebtRemediationFunction(DebtRemediationFunction.createConstantPerIssue(Duration.create(25L)));
activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO);
initModuleIssues();
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
+import org.sonar.api.batch.debt.internal.DefaultDebtCharacteristic;
+import org.sonar.api.batch.debt.internal.DefaultDebtModel;
import org.sonar.api.batch.rule.DebtRemediationFunction;
import org.sonar.api.batch.rule.Rule;
import org.sonar.api.batch.rule.RuleParam;
import org.sonar.api.config.Settings;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.Severity;
-import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
import org.sonar.api.utils.Duration;
import org.sonar.api.utils.Durations;
import org.sonar.core.persistence.AbstractDaoTestCase;
import org.sonar.core.rule.RuleDao;
-import org.sonar.core.technicaldebt.DefaultTechnicalDebtModel;
import static org.fest.assertions.Assertions.assertThat;
import static org.fest.assertions.Fail.fail;
RuleDao ruleDao;
- DefaultTechnicalDebtModel debtModel;
+ DefaultDebtModel debtModel;
RulesProvider provider;
@Before
public void setUp() throws Exception {
- debtModel = new DefaultTechnicalDebtModel();
- debtModel.addRootCharacteristic(new DefaultCharacteristic()
- .setId(101)
- .setKey("EFFICIENCY")
- .setName("Efficiency")
- .setParent(new DefaultCharacteristic()
+ debtModel = new DefaultDebtModel()
+ .addCharacteristic(new DefaultDebtCharacteristic()
.setId(100)
.setKey("MEMORY_EFFICIENCY")
- .setName("Memory use")));
- debtModel.addRootCharacteristic(new DefaultCharacteristic()
- .setId(103)
- .setKey("PORTABILITY")
- .setName("Portability")
- .setParent(new DefaultCharacteristic()
+ .setName("Memory use")
+ .setOrder(1))
+ .addCharacteristic(new DefaultDebtCharacteristic()
+ .setId(101)
+ .setKey("EFFICIENCY")
+ .setName("Efficiency")
+ .setParentId(100));
+ debtModel
+ .addCharacteristic(new DefaultDebtCharacteristic()
.setId(102)
.setKey("COMPILER_RELATED_PORTABILITY")
- .setName("Compiler")));
+ .setName("Compiler")
+ .setOrder(1))
+ .addCharacteristic(new DefaultDebtCharacteristic()
+ .setId(103)
+ .setKey("PORTABILITY")
+ .setName("Portability")
+ .setParentId(102));
durations = new Durations(new Settings().setProperty("sonar.technicalDebt.hoursInDay", 8), null);
ruleDao = new RuleDao(getMyBatis());
Rules rules = provider.provide(ruleDao, debtModel, durations);
Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
- assertThat(rule.debtCharacteristic()).isEqualTo("EFFICIENCY");
+ assertThat(rule.debtSubCharacteristic()).isEqualTo("EFFICIENCY");
assertThat(rule.debtRemediationFunction()).isEqualTo(DebtRemediationFunction.createLinearWithOffset(Duration.decode("5d", 8), Duration.decode("10h", 8)));
}
Rules rules = provider.provide(ruleDao, debtModel, durations);
Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
- assertThat(rule.debtCharacteristic()).isEqualTo("PORTABILITY");
+ assertThat(rule.debtSubCharacteristic()).isEqualTo("PORTABILITY");
assertThat(rule.debtRemediationFunction()).isEqualTo(DebtRemediationFunction.createLinear(Duration.decode("2h", 8)));
}
// As both default columns and user columns on debt are set, user debt columns should be used
Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
- assertThat(rule.debtCharacteristic()).isEqualTo("PORTABILITY");
+ assertThat(rule.debtSubCharacteristic()).isEqualTo("PORTABILITY");
assertThat(rule.debtRemediationFunction()).isEqualTo(DebtRemediationFunction.createLinear(Duration.decode("2h", 8)));
}
// As both default columns and user columns on debt are set, user debt columns should be used
Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
- assertThat(rule.debtCharacteristic()).isEqualTo("PORTABILITY");
+ assertThat(rule.debtSubCharacteristic()).isEqualTo("PORTABILITY");
assertThat(rule.debtRemediationFunction()).isEqualTo(DebtRemediationFunction.createLinear(Duration.decode("2h", 8)));
}
// As both default columns and user columns on debt are set, user debt columns should be used
Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
- assertThat(rule.debtCharacteristic()).isEqualTo("PORTABILITY");
+ assertThat(rule.debtSubCharacteristic()).isEqualTo("PORTABILITY");
assertThat(rule.debtRemediationFunction()).isEqualTo(DebtRemediationFunction.createLinear(Duration.decode("2h", 8)));
}
Rules rules = provider.provide(ruleDao, debtModel, durations);
Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
- assertThat(rule.debtCharacteristic()).isNull();
+ assertThat(rule.debtSubCharacteristic()).isNull();
assertThat(rule.debtRemediationFunction()).isNull();
}
Rules rules = provider.provide(ruleDao, debtModel, durations);
Rule rule = rules.find(RuleKey.of("checkstyle", "AvoidNull"));
- assertThat(rule.debtCharacteristic()).isNull();
+ assertThat(rule.debtSubCharacteristic()).isNull();
assertThat(rule.debtRemediationFunction()).isNull();
}
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
+import org.sonar.api.batch.debt.DebtCharacteristic;
+import org.sonar.api.batch.debt.DebtModel;
+import org.sonar.api.batch.debt.internal.DefaultDebtCharacteristic;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.technicaldebt.batch.TechnicalDebtModel;
import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
import org.sonar.api.technicaldebt.batch.internal.DefaultRequirement;
import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
-import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class DefaultTechnicalDebtModel implements TechnicalDebtModel {
- private Collection<DefaultCharacteristic> rootCharacteristics;
+ private final DebtModel model;
- public DefaultTechnicalDebtModel() {
- rootCharacteristics = newArrayList();
- }
-
- public DefaultTechnicalDebtModel addRootCharacteristic(DefaultCharacteristic characteristic) {
- rootCharacteristics.add(characteristic);
- return this;
+ public DefaultTechnicalDebtModel(DebtModel model) {
+ this.model = model;
}
public List<DefaultCharacteristic> rootCharacteristics() {
- return newArrayList(Iterables.filter(rootCharacteristics, new Predicate<DefaultCharacteristic>() {
+ return newArrayList(Iterables.filter(characteristics(), new Predicate<DefaultCharacteristic>() {
@Override
public boolean apply(DefaultCharacteristic input) {
return input.isRoot();
}
@CheckForNull
- public DefaultCharacteristic characteristicById(final Integer id){
+ public DefaultCharacteristic characteristicById(final Integer id) {
return Iterables.find(characteristics(), new Predicate<DefaultCharacteristic>() {
@Override
public boolean apply(DefaultCharacteristic input) {
}
@CheckForNull
- public DefaultRequirement requirementsById(final Integer id){
+ public DefaultRequirement requirementsById(final Integer id) {
return null;
}
public List<DefaultCharacteristic> characteristics() {
List<DefaultCharacteristic> flatCharacteristics = newArrayList();
- for (DefaultCharacteristic rootCharacteristic : rootCharacteristics) {
- flatCharacteristics.add(rootCharacteristic);
- for (DefaultCharacteristic characteristic : rootCharacteristic.children()) {
- flatCharacteristics.add(characteristic);
+ for (DebtCharacteristic characteristic : model.characteristics()) {
+ DefaultCharacteristic root = toDefaultCharacteristic((DefaultDebtCharacteristic) characteristic, null);
+ flatCharacteristics.add(root);
+ for (DebtCharacteristic subCharacteristic : model.subCharacteristics(characteristic.key())) {
+ flatCharacteristics.add(toDefaultCharacteristic((DefaultDebtCharacteristic) subCharacteristic, root));
}
}
return flatCharacteristics;
return Collections.emptyList();
}
- public boolean isEmpty(){
- return rootCharacteristics.isEmpty();
+ public boolean isEmpty() {
+ return model.allCharacteristics().isEmpty();
+ }
+
+ private static DefaultCharacteristic toDefaultCharacteristic(DefaultDebtCharacteristic debtCharacteristic, @Nullable DefaultCharacteristic parentCharacteristic) {
+ return new DefaultCharacteristic()
+ .setId(debtCharacteristic.id())
+ .setKey(debtCharacteristic.key())
+ .setName(debtCharacteristic.name())
+ .setOrder(debtCharacteristic.order())
+ .setParent(parentCharacteristic)
+ .setRoot(parentCharacteristic)
+ .setCreatedAt(debtCharacteristic.createdAt())
+ .setUpdatedAt(debtCharacteristic.updatedAt());
}
}
import org.junit.Before;
import org.junit.Test;
+import org.sonar.api.batch.debt.internal.DefaultDebtCharacteristic;
+import org.sonar.api.batch.debt.internal.DefaultDebtModel;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
@Before
public void setUp() throws Exception {
- sqaleModel = new DefaultTechnicalDebtModel();
+ DefaultDebtModel debtModel = new DefaultDebtModel();
+ debtModel.addCharacteristic(
+ new DefaultDebtCharacteristic().setId(1)
+ .setKey("MEMORY_EFFICIENCY")
+ .setName("Memory use")
+ .setOrder(1)
+ );
+ debtModel.addSubCharacteristic(
+ new DefaultDebtCharacteristic().setId(2)
+ .setKey("EFFICIENCY")
+ .setName("Efficiency")
+ .setParentId(1),
+ "MEMORY_EFFICIENCY"
+ );
+ sqaleModel = new DefaultTechnicalDebtModel(debtModel);
}
@Test
- public void get_root_characteristics() throws Exception {
- DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic()
- .setKey("MEMORY_EFFICIENCY")
- .setName("Memory use");
-
- new DefaultCharacteristic()
- .setKey("EFFICIENCY")
- .setName("Efficiency")
- .setParent(rootCharacteristic);
-
- sqaleModel.addRootCharacteristic(rootCharacteristic);
-
+ public void get_characteristics() throws Exception {
assertThat(sqaleModel.rootCharacteristics()).hasSize(1);
+
DefaultCharacteristic resultRootCharacteristic = sqaleModel.rootCharacteristics().get(0);
- assertThat(resultRootCharacteristic).isEqualTo(rootCharacteristic);
+ assertThat(resultRootCharacteristic.id()).isEqualTo(1);
+ assertThat(resultRootCharacteristic.key()).isEqualTo("MEMORY_EFFICIENCY");
+ assertThat(resultRootCharacteristic.name()).isEqualTo("Memory use");
+ assertThat(resultRootCharacteristic.order()).isEqualTo(1);
+ assertThat(resultRootCharacteristic.children()).hasSize(1);
+ assertThat(resultRootCharacteristic.parent()).isNull();
+ assertThat(resultRootCharacteristic.root()).isNull();
}
@Test
public void get_characteristic_by_key() throws Exception {
- DefaultCharacteristic rootCharacteristic = new DefaultCharacteristic()
- .setKey("MEMORY_EFFICIENCY")
- .setName("Memory use");
-
- DefaultCharacteristic characteristic = new DefaultCharacteristic()
- .setKey("EFFICIENCY")
- .setName("Efficiency")
- .setParent(rootCharacteristic);
-
- sqaleModel.addRootCharacteristic(rootCharacteristic);
-
- assertThat(sqaleModel.characteristicByKey("MEMORY_EFFICIENCY")).isEqualTo(rootCharacteristic);
- assertThat(sqaleModel.characteristicByKey("EFFICIENCY")).isEqualTo(characteristic);
- assertThat(sqaleModel.characteristicByKey("EFFICIENCY").parent()).isEqualTo(rootCharacteristic);
+ assertThat(sqaleModel.characteristicByKey("MEMORY_EFFICIENCY")).isNotNull();
+ assertThat(sqaleModel.characteristicByKey("EFFICIENCY")).isNotNull();
+ assertThat(sqaleModel.characteristicByKey("EFFICIENCY").parent()).isNotNull();
assertThat(sqaleModel.characteristicByKey("UNKNOWN")).isNull();
}
+ @Test
+ public void characteristic_by_id() throws Exception {
+ assertThat(sqaleModel.characteristicById(1)).isNotNull();
+ assertThat(sqaleModel.characteristicById(2)).isNotNull();
+ assertThat(sqaleModel.characteristicById(123)).isNull();
+ }
+
@Test
public void get_requirement_by_rule_key_always_return_null() throws Exception {
assertThat(sqaleModel.requirementsByRule(RuleKey.of("checkstyle", "Regexp"))).isNull();
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.api.batch.debt;
+
+import javax.annotation.CheckForNull;
+
+/**
+ * @since 4.3
+ */
+public interface DebtCharacteristic {
+ String key();
+
+ String name();
+
+ @CheckForNull
+ Integer order();
+
+ boolean isSub();
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.api.batch.debt;
+
+import javax.annotation.CheckForNull;
+
+import java.util.List;
+
+/**
+ * This class can be used to retrieve characteristics or sub-characteristics from the technical debt model during analysis.
+ *
+ * Unfortunately, this class cannot be used to set characteristic on {@link org.sonar.api.measures.Measure},
+ * because the Measure API still uses deprecated {@link org.sonar.api.technicaldebt.batch.Characteristic}.
+ *
+ * @since 4.3
+ */
+public interface DebtModel {
+
+ /**
+ * Return only characteristics
+ */
+ List<DebtCharacteristic> characteristics();
+
+ /**
+ * Return sub-characteristics of a characteristic
+ */
+ List<DebtCharacteristic> subCharacteristics(String characteristicKey);
+
+ /**
+ * Return characteristics and sub-characteristics
+ */
+ List<DebtCharacteristic> allCharacteristics();
+
+ /**
+ * Return a characteristic or a sub-characteristic by a key
+ */
+ @CheckForNull
+ DebtCharacteristic characteristicByKey(String key);
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.api.batch.debt.internal;
+
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.sonar.api.batch.debt.DebtCharacteristic;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+import java.util.Date;
+
+public class DefaultDebtCharacteristic implements DebtCharacteristic {
+
+ private Integer id;
+ private String key;
+ private String name;
+ private Integer order;
+ private Integer parentId;
+ private Date createdAt;
+ private Date updatedAt;
+
+ public Integer id() {
+ return id;
+ }
+
+ public DefaultDebtCharacteristic setId(Integer id) {
+ this.id = id;
+ return this;
+ }
+
+ @Override
+ public String key() {
+ return key;
+ }
+
+ public DefaultDebtCharacteristic setKey(String key) {
+ this.key = key;
+ return this;
+ }
+
+ @Override
+ public String name() {
+ return name;
+ }
+
+ public DefaultDebtCharacteristic setName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ @Override
+ @CheckForNull
+ public Integer order() {
+ return order;
+ }
+
+ public DefaultDebtCharacteristic setOrder(@Nullable Integer order) {
+ this.order = order;
+ return this;
+ }
+
+ @CheckForNull
+ public Integer parentId() {
+ return parentId;
+ }
+
+ public DefaultDebtCharacteristic setParentId(@Nullable Integer parentId) {
+ this.parentId = parentId;
+ return this;
+ }
+
+ public Date createdAt() {
+ return createdAt;
+ }
+
+ public DefaultDebtCharacteristic setCreatedAt(Date createdAt) {
+ this.createdAt = createdAt;
+ return this;
+ }
+
+ @CheckForNull
+ public Date updatedAt() {
+ return updatedAt;
+ }
+
+ public DefaultDebtCharacteristic setUpdatedAt(@Nullable Date updatedAt) {
+ this.updatedAt = updatedAt;
+ return this;
+ }
+
+ @Override
+ public boolean isSub(){
+ return parentId != null;
+ }
+
+ @Override
+ public String toString() {
+ return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.api.batch.debt.internal;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimap;
+import org.sonar.api.batch.debt.DebtCharacteristic;
+import org.sonar.api.batch.debt.DebtModel;
+
+import javax.annotation.CheckForNull;
+
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+public class DefaultDebtModel implements DebtModel {
+
+ /**
+ * Sub-characteristics list can be retrieved with the characteristic key
+ * Characteristics list can be retrieved by with the null key
+ */
+ private Multimap<String, DebtCharacteristic> characteristicsByKey;
+
+ public DefaultDebtModel() {
+ characteristicsByKey = ArrayListMultimap.create();
+ }
+
+ public DefaultDebtModel addCharacteristic(DebtCharacteristic characteristic) {
+ characteristicsByKey.put(null, characteristic);
+ return this;
+ }
+
+ public DefaultDebtModel addSubCharacteristic(DebtCharacteristic subCharacteristic, String characteristicKey) {
+ characteristicsByKey.put(characteristicKey, subCharacteristic);
+ return this;
+ }
+
+ @Override
+ public List<DebtCharacteristic> characteristics() {
+ return newArrayList(characteristicsByKey.get(null));
+ }
+
+ @Override
+ public List<DebtCharacteristic> subCharacteristics(String characteristicKey) {
+ return newArrayList(characteristicsByKey.get(characteristicKey));
+ }
+
+ @Override
+ public List<DebtCharacteristic> allCharacteristics() {
+ return newArrayList(characteristicsByKey.values());
+ }
+
+ @Override
+ @CheckForNull
+ public DebtCharacteristic characteristicByKey(final String key) {
+ return Iterables.find(characteristicsByKey.values(), new Predicate<DebtCharacteristic>() {
+ @Override
+ public boolean apply(DebtCharacteristic input) {
+ return key.equals(input.key());
+ }
+ }, null);
+ }
+
+ @CheckForNull
+ public DebtCharacteristic characteristicById(final int id) {
+ return Iterables.find(characteristicsByKey.values(), new Predicate<DebtCharacteristic>() {
+ @Override
+ public boolean apply(DebtCharacteristic input) {
+ return id == ((DefaultDebtCharacteristic) input).id();
+ }
+ }, null);
+ }
+}
RuleStatus status();
/**
- * Characteristic key.
+ * Sub characteristic key.
*
* @since 4.3
*/
@CheckForNull
- String debtCharacteristic();
+ String debtSubCharacteristic();
/**
* Remediation function : can by Linear (with a coefficient), Linear with offset (with a coefficient and an offset) or Constant per issue (with an offset)
private final RuleKey key;
private final Integer id;
- private final String name, severity, description, metadata, debtCharacteristic;
+ private final String name, severity, description, metadata, debtSubCharacteristic;
private final RuleStatus status;
private final DebtRemediationFunction debtRemediationFunction;
this.description = newRule.description;
this.metadata = newRule.metadata;
this.status = newRule.status;
- this.debtCharacteristic = newRule.debtCharacteristic;
+ this.debtSubCharacteristic = newRule.debtSubCharacteristic;
this.debtRemediationFunction = newRule.debtRemediationFunction;
ImmutableMap.Builder<String, RuleParam> builder = ImmutableMap.builder();
}
@Override
- public String debtCharacteristic() {
- return debtCharacteristic;
+ public String debtSubCharacteristic() {
+ return debtSubCharacteristic;
}
@Override
final RuleKey key;
Integer id;
- String name, description, severity = DEFAULT_SEVERITY, metadata, debtCharacteristic;
+ String name, description, severity = DEFAULT_SEVERITY, metadata, debtSubCharacteristic;
DebtRemediationFunction debtRemediationFunction;
RuleStatus status = RuleStatus.defaultStatus();
Map<String, NewRuleParam> params = new HashMap<String, NewRuleParam>();
return this;
}
- public NewRule setDebtCharacteristic(@Nullable String c) {
- this.debtCharacteristic = c;
+ public NewRule setDebtSubCharacteristic(@Nullable String c) {
+ this.debtSubCharacteristic = c;
return this;
}
import javax.annotation.CheckForNull;
-import java.util.Date;
-
/**
* @since 4.3
*/
public interface DebtCharacteristic {
- Integer id();
String key();
@CheckForNull
Integer order();
- @CheckForNull
- Integer parentId();
-
- Date createdAt();
-
- @CheckForNull
- Date updatedAt();
+ boolean isSub();
}
*/
List<DebtCharacteristic> characteristics();
- DebtCharacteristic characteristicById(int id);
+ /**
+ * Return a characteristic or a sub-characteristic by its key
+ */
+ DebtCharacteristic characteristicByKey(String key);
}
private Date createdAt;
private Date updatedAt;
- @Override
public Integer id() {
return id;
}
return this;
}
- @Override
@CheckForNull
public Integer parentId() {
return parentId;
return this;
}
- @Override
public Date createdAt() {
return createdAt;
}
return this;
}
- @Override
@CheckForNull
public Date updatedAt() {
return updatedAt;
return this;
}
+ @Override
+ public boolean isSub(){
+ return parentId != null;
+ }
+
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
/**
* @since 4.1
+ * @deprecated since 4.3
*/
+@Deprecated
public interface Characteristic {
Integer id();
package org.sonar.api.technicaldebt.batch;
+import org.sonar.api.BatchComponent;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.technicaldebt.batch.internal.DefaultCharacteristic;
/**
* @since 4.1
* Used by Views plugin
+ * @deprecated since 4.3
*/
-public interface TechnicalDebtModel {
+@Deprecated
+public interface TechnicalDebtModel extends BatchComponent {
@CheckForNull
Characteristic characteristicById(Integer id);
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.api.batch.debt.internal;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class DefaultDebtModelTest {
+
+ private DefaultDebtModel debtModel;
+
+ @Before
+ public void setUp() throws Exception {
+ debtModel = new DefaultDebtModel()
+ .addCharacteristic(
+ new DefaultDebtCharacteristic().setId(1)
+ .setKey("MEMORY_EFFICIENCY")
+ .setName("Memory use")
+ .setOrder(1)
+ )
+ .addSubCharacteristic(
+ new DefaultDebtCharacteristic().setId(2)
+ .setKey("EFFICIENCY")
+ .setName("Efficiency")
+ .setParentId(1),
+ "MEMORY_EFFICIENCY"
+ );
+ }
+
+ @Test
+ public void all_characteristics() throws Exception {
+ assertThat(debtModel.allCharacteristics()).hasSize(2);
+ }
+
+ @Test
+ public void characteristics() throws Exception {
+ assertThat(debtModel.characteristics()).hasSize(1);
+ }
+
+ @Test
+ public void sub_characteristics() throws Exception {
+ assertThat(debtModel.subCharacteristics("MEMORY_EFFICIENCY")).hasSize(1);
+ }
+
+ @Test
+ public void characteristic_by_id() throws Exception {
+ DefaultDebtCharacteristic debtCharacteristic = (DefaultDebtCharacteristic) debtModel.characteristicById(1);
+ assertThat(debtCharacteristic).isNotNull();
+ assertThat(debtCharacteristic.id()).isEqualTo(1);
+ assertThat(debtCharacteristic.key()).isEqualTo("MEMORY_EFFICIENCY");
+ assertThat(debtCharacteristic.name()).isEqualTo("Memory use");
+ assertThat(debtCharacteristic.order()).isEqualTo(1);
+ assertThat(debtCharacteristic.parentId()).isNull();
+ assertThat(debtCharacteristic.isSub()).isFalse();
+ }
+
+ @Test
+ public void characteristic_by_key() throws Exception {
+ DefaultDebtCharacteristic debtCharacteristic = (DefaultDebtCharacteristic) debtModel.characteristicByKey("EFFICIENCY");
+ assertThat(debtCharacteristic).isNotNull();
+ assertThat(debtCharacteristic.id()).isEqualTo(2);
+ assertThat(debtCharacteristic.key()).isEqualTo("EFFICIENCY");
+ assertThat(debtCharacteristic.name()).isEqualTo("Efficiency");
+ assertThat(debtCharacteristic.order()).isNull();
+ assertThat(debtCharacteristic.parentId()).isEqualTo(1);
+ assertThat(debtCharacteristic.isSub()).isTrue();
+ }
+}
newSquid1.setMetadata("foo=bar");
newSquid1.setSeverity(Severity.CRITICAL);
newSquid1.setStatus(RuleStatus.BETA);
- newSquid1.setDebtCharacteristic("COMPILER");
+ newSquid1.setDebtSubCharacteristic("COMPILER");
newSquid1.setDebtRemediationFunction(DebtRemediationFunction.create(DebtRemediationFunction.Type.LINEAR_OFFSET, Duration.create(10), Duration.create(60)));
newSquid1.addParam("min");
newSquid1.addParam("max").setDescription("Maximum");
assertThat(squid1.metadata()).isEqualTo("foo=bar");
assertThat(squid1.status()).isEqualTo(RuleStatus.BETA);
assertThat(squid1.severity()).isEqualTo(Severity.CRITICAL);
- assertThat(squid1.debtCharacteristic()).isEqualTo("COMPILER");
+ assertThat(squid1.debtSubCharacteristic()).isEqualTo("COMPILER");
assertThat(squid1.debtRemediationFunction().type()).isEqualTo(DebtRemediationFunction.Type.LINEAR_OFFSET);
assertThat(squid1.debtRemediationFunction().coefficient()).isEqualTo(Duration.create(10));
assertThat(squid1.debtRemediationFunction().offset()).isEqualTo(Duration.create(60));
- assertThat(squid1.debtCharacteristic()).isEqualTo("COMPILER");
+ assertThat(squid1.debtSubCharacteristic()).isEqualTo("COMPILER");
assertThat(squid1.params()).hasSize(2);
assertThat(squid1.param("min").key()).isEqualTo("min");
assertThat(squid1.param("min").description()).isNull();
assertThat(squid2.metadata()).isNull();
assertThat(squid2.status()).isEqualTo(RuleStatus.defaultStatus());
assertThat(squid2.severity()).isEqualTo(Severity.defaultSeverity());
- assertThat(squid2.debtCharacteristic()).isNull();
+ assertThat(squid2.debtSubCharacteristic()).isNull();
assertThat(squid2.debtRemediationFunction()).isNull();
assertThat(squid2.params()).isEmpty();
}