@Test
public void convert_simple_values() {
- checkValues(converter.fromMinutes(15L), 15L, 0L, 0L);
- checkValues(converter.fromMinutes(120L), 0L, 2L, 0L);
- checkValues(converter.fromMinutes(720L), 0L, 0L, 1L);
+ checkValues(converter.fromMinutes(15L), 15, 0, 0);
+ checkValues(converter.fromMinutes(120L), 0, 2, 0);
+ checkValues(converter.fromMinutes(720L), 0, 0, 1);
}
@Test
public void convert_complex_values() {
- checkValues(converter.fromMinutes(70L), 10L, 1L, 0L);
- checkValues(converter.fromMinutes(730L), 10L, 0L, 1L);
- checkValues(converter.fromMinutes(790L), 10L, 1L, 1L);
+ checkValues(converter.fromMinutes(70L), 10, 1, 0);
+ checkValues(converter.fromMinutes(730L), 10, 0, 1);
+ checkValues(converter.fromMinutes(790L), 10, 1, 1);
}
@Test
assertThat(converter.toDays(TechnicalDebt.of(45, 6, 1))).isEqualTo(1.5625);
}
- private void checkValues(TechnicalDebt technicalDebt, Long expectedMinutes, Long expectedHours, Long expectedDays) {
+ private void checkValues(TechnicalDebt technicalDebt, int expectedMinutes, int expectedHours, int expectedDays) {
assertThat(technicalDebt.minutes()).isEqualTo(expectedMinutes);
assertThat(technicalDebt.hours()).isEqualTo(expectedHours);
assertThat(technicalDebt.days()).isEqualTo(expectedDays);
this.newValue = newValue;
}
+ @CheckForNull
public T oldValue() {
return oldValue;
}
+ @CheckForNull
public T newValue() {
return newValue;
}
return days * DAY + hours * HOUR + minutes * MINUTE;
}
- public long days() {
+ public int days() {
return days;
}
- public long hours() {
+ public int hours() {
return hours;
}
- public long minutes() {
+ public int minutes() {
return minutes;
}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.server.issue;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+public class IssueChangelogDiffFormat {
+
+ private String oldValue, newValue;
+
+ public IssueChangelogDiffFormat(@Nullable String oldValue, @Nullable String newValue) {
+ this.oldValue = oldValue;
+ this.newValue = newValue;
+ }
+
+ @CheckForNull
+ public String oldValue() {
+ return oldValue;
+ }
+
+ @CheckForNull
+ public String newValue() {
+ return newValue;
+ }
+
+}
import org.sonar.api.ServerComponent;
import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.api.technicaldebt.TechnicalDebt;
import org.sonar.core.i18n.I18nManager;
+import org.sonar.core.issue.IssueUpdater;
+import org.sonar.server.technicaldebt.TechnicalDebtFormatter;
+import java.io.Serializable;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class IssueChangelogFormatter implements ServerComponent {
private final I18nManager i18nManager;
+ private final TechnicalDebtFormatter technicalDebtFormatter;
- public IssueChangelogFormatter(I18nManager i18nManager) {
+ public IssueChangelogFormatter(I18nManager i18nManager, TechnicalDebtFormatter technicalDebtFormatter) {
this.i18nManager = i18nManager;
+ this.technicalDebtFormatter = technicalDebtFormatter;
}
public List<String> format(Locale locale, FieldDiffs diffs) {
for (Map.Entry<String, FieldDiffs.Diff> entry : diffs.diffs().entrySet()) {
StringBuilder message = new StringBuilder();
String key = entry.getKey();
- FieldDiffs.Diff diff = entry.getValue();
- if (diff.newValue() != null && !diff.newValue().equals("")) {
- message.append(i18nManager.message(locale, "issue.changelog.changed_to", null, i18nManager.message(locale, "issue.changelog.field." + key, null), diff.newValue()));
+ IssueChangelogDiffFormat diffFormat = format(locale, key, entry.getValue());
+ if (diffFormat.newValue() != null) {
+ message.append(i18nManager.message(locale, "issue.changelog.changed_to", null, i18nManager.message(locale, "issue.changelog.field." + key, null), diffFormat.newValue()));
} else {
message.append(i18nManager.message(locale, "issue.changelog.removed", null, i18nManager.message(locale, "issue.changelog.field." + key, null)));
}
- if (diff.oldValue() != null && !diff.oldValue().equals("")) {
+ if (diffFormat.oldValue() != null) {
message.append(" (");
- message.append(i18nManager.message(locale, "issue.changelog.was", null, diff.oldValue()));
+ message.append(i18nManager.message(locale, "issue.changelog.was", null, diffFormat.oldValue()));
message.append(")");
}
result.add(message.toString());
return result;
}
+ private IssueChangelogDiffFormat format(Locale locale, String key, FieldDiffs.Diff diff) {
+ Serializable newValue = diff.newValue();
+ Serializable oldValue = diff.oldValue();
+
+ String newValueString = newValue != null && !newValue.equals("") ? diff.newValue().toString() : null;
+ String oldValueString = oldValue != null && !oldValue.equals("") ? diff.oldValue().toString() : null;
+ if (IssueUpdater.TECHNICAL_DEBT.equals(key)) {
+ if (newValueString != null) {
+ newValueString = technicalDebtFormatter.format(locale, TechnicalDebt.fromLong(Long.parseLong(newValueString)));
+ }
+ if (oldValueString != null) {
+ oldValueString = technicalDebtFormatter.format(locale, TechnicalDebt.fromLong(Long.parseLong(oldValueString)));
+ }
+ }
+ return new IssueChangelogDiffFormat(oldValueString, newValueString);
+ }
+
}
import org.sonar.server.rules.ProfilesConsole;
import org.sonar.server.rules.RulesConsole;
import org.sonar.server.startup.*;
+import org.sonar.server.technicaldebt.InternalRubyTechnicalDebtService;
+import org.sonar.server.technicaldebt.TechnicalDebtFormatter;
import org.sonar.server.text.MacroInterpreter;
import org.sonar.server.text.RubyTextService;
import org.sonar.server.ui.*;
servicesContainer.addSingleton(RubyRuleService.class);
// technical debt
+ servicesContainer.addSingleton(InternalRubyTechnicalDebtService.class);
servicesContainer.addSingleton(TechnicalDebtManager.class);
servicesContainer.addSingleton(TechnicalDebtModelRepository.class);
servicesContainer.addSingleton(TechnicalDebtXMLImporter.class);
servicesContainer.addSingleton(TechnicalDebtConverter.class);
+ servicesContainer.addSingleton(TechnicalDebtFormatter.class);
// text
servicesContainer.addSingleton(MacroInterpreter.class);
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.server.technicaldebt;
+
+import org.sonar.api.ServerComponent;
+import org.sonar.api.technicaldebt.TechnicalDebt;
+import org.sonar.server.user.UserSession;
+
+public class InternalRubyTechnicalDebtService implements ServerComponent {
+
+ private final TechnicalDebtFormatter technicalDebtFormatter;
+
+ public InternalRubyTechnicalDebtService(TechnicalDebtFormatter technicalDebtFormatter) {
+ this.technicalDebtFormatter = technicalDebtFormatter;
+ }
+
+ public String format(TechnicalDebt technicalDebt){
+ return technicalDebtFormatter.format(UserSession.get().locale(), technicalDebt);
+ }
+
+ public TechnicalDebt toTechnicalDebt(String technicalDebtInLong){
+ return TechnicalDebt.fromLong(Long.parseLong(technicalDebtInLong));
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.server.technicaldebt;
+
+import org.sonar.api.ServerComponent;
+import org.sonar.api.technicaldebt.TechnicalDebt;
+import org.sonar.core.i18n.I18nManager;
+
+import java.util.Locale;
+
+public class TechnicalDebtFormatter implements ServerComponent {
+
+ private final I18nManager i18nManager;
+
+ public TechnicalDebtFormatter(I18nManager i18nManager) {
+ this.i18nManager = i18nManager;
+ }
+
+ public String format(Locale locale, TechnicalDebt technicalDebt) {
+ StringBuilder message = new StringBuilder();
+ if (technicalDebt.days() > 0) {
+ message.append(i18nManager.message(locale, "issue.technical_debt.x_days", null, technicalDebt.days()));
+ }
+ if (technicalDebt.hours() > 0) {
+ if (message.length() > 0) {
+ message.append(" ");
+ }
+ message.append(i18nManager.message(locale, "issue.technical_debt.x_hours", null, technicalDebt.hours()));
+ }
+ // Do not display minutes if days is not null to not have too much information
+ if (technicalDebt.minutes() > 0 && technicalDebt.days() == 0) {
+ if (message.length() > 0) {
+ message.append(" ");
+ }
+ message.append(i18nManager.message(locale, "issue.technical_debt.x_minutes", null, technicalDebt.minutes()));
+ }
+ return message.toString();
+ }
+}
component(Java::OrgSonarServerPermission::InternalPermissionTemplateService.java_class)
end
+ def self.technical_debt
+ component(Java::OrgSonarServerTechnicaldebt::InternalRubyTechnicalDebtService.java_class)
+ end
private
diff = entry.getValue()
hash_diff = {}
hash_diff[:key] = key
- hash_diff[:newValue] = diff.newValue() if diff.newValue.present?
- hash_diff[:oldValue] = diff.oldValue() if diff.oldValue.present?
+ if key == 'technicalDebt'
+ hash_diff[:newValue] = technical_debt_to_hash(Internal.technical_debt.toTechnicalDebt(diff.newValue())) if diff.newValue.present?
+ hash_diff[:oldValue] = technical_debt_to_hash(Internal.technical_debt.toTechnicalDebt(diff.oldValue())) if diff.oldValue.present?
+ else
+ hash_diff[:newValue] = diff.newValue() if diff.newValue.present?
+ hash_diff[:oldValue] = diff.oldValue() if diff.oldValue.present?
+ end
hash_change[:diffs] << hash_diff
end
<% if issue.technicalDebt %>
<img src="<%= ApplicationController.root_context -%>/images/sep12.png"/>
- <% technical_debt = issue.technicalDebt
- days = technical_debt.days
- hours = technical_debt.hours
- minutes = technical_debt.minutes
- message = ''
- message += message('issue.technical_debt.x_days', :params => days) + ' ' if days > 0
- message += message('issue.technical_debt.x_hours', :params => hours) + ' ' if hours > 0
- # Do not display minutes if days is not null to not have too much information
- message += message('issue.technical_debt.x_minutes', :params => minutes) if minutes > 0 && days == 0
- %>
<%= message('issue.technical_debt') -%> <a href="#" onclick="return toggleTechnicalDebt(this)" class="gray issue-technicaldebt-link"
- id="toggle-issue-technicaldebt"><%= message -%></a>
+ id="toggle-issue-technicaldebt"><%= Internal.technical_debt.format(issue.technicalDebt) -%></a>
<% end %>
</div>
import org.sonar.server.user.UserSession;
import java.util.Collections;
+import java.util.Locale;
import java.util.Map;
import static com.google.common.collect.Lists.newArrayList;
verify(issueBulkChangeService).execute(any(IssueBulkChangeQuery.class), any(UserSession.class));
}
+ @Test
+ public void format_changelog() {
+ FieldDiffs fieldDiffs = new FieldDiffs();
+ service.formatChangelog(fieldDiffs);
+ verify(issueChangelogFormatter).format(any(Locale.class), eq(fieldDiffs));
+ }
+
private void checkBadRequestException(Exception e, String key, Object... params) {
BadRequestException exception = (BadRequestException) e;
assertThat(exception.l10nKey()).isEqualTo(key);
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.api.technicaldebt.TechnicalDebt;
import org.sonar.core.i18n.I18nManager;
+import org.sonar.server.technicaldebt.TechnicalDebtFormatter;
import java.util.List;
import java.util.Locale;
@Mock
private I18nManager i18nManager;
+ @Mock
+ private TechnicalDebtFormatter technicalDebtFormatter;
+
private IssueChangelogFormatter formatter;
@Before
public void before(){
- formatter = new IssueChangelogFormatter(i18nManager);
+ formatter = new IssueChangelogFormatter(i18nManager, technicalDebtFormatter);
}
@Test
assertThat(message).isEqualTo("Severity removed");
}
+ @Test
+ public void format_technical_debt_with_old_and_new_value(){
+ FieldDiffs diffs = new FieldDiffs();
+ diffs.setDiff("technicalDebt", "500", "10000");
+
+ when(technicalDebtFormatter.format(DEFAULT_LOCALE, TechnicalDebt.of(0, 5, 0))).thenReturn("5 hours");
+ when(technicalDebtFormatter.format(DEFAULT_LOCALE, TechnicalDebt.of(0, 0, 1))).thenReturn("1 days");
+
+ when(i18nManager.message(DEFAULT_LOCALE, "issue.changelog.field.technicalDebt", null)).thenReturn("Technical Debt");
+ when(i18nManager.message(DEFAULT_LOCALE, "issue.changelog.changed_to", null, "Technical Debt", "1 days")).thenReturn("Technical Debt changed to 1 days");
+ when(i18nManager.message(DEFAULT_LOCALE, "issue.changelog.was", null, "5 hours")).thenReturn("was 5 hours");
+
+ List<String> result = formatter.format(DEFAULT_LOCALE, diffs);
+ assertThat(result).hasSize(1);
+ String message = result.get(0);
+ assertThat(message).isEqualTo("Technical Debt changed to 1 days (was 5 hours)");
+ }
+
+ @Test
+ public void format_technical_debt_with_new_value_only(){
+ FieldDiffs diffs = new FieldDiffs();
+ diffs.setDiff("technicalDebt", null, "10000");
+
+ when(technicalDebtFormatter.format(DEFAULT_LOCALE, TechnicalDebt.of(0, 0, 1))).thenReturn("1 days");
+
+ when(i18nManager.message(DEFAULT_LOCALE, "issue.changelog.field.technicalDebt", null)).thenReturn("Technical Debt");
+ when(i18nManager.message(DEFAULT_LOCALE, "issue.changelog.changed_to", null, "Technical Debt", "1 days")).thenReturn("Technical Debt changed to 1 days");
+
+ List<String> result = formatter.format(DEFAULT_LOCALE, diffs);
+ assertThat(result).hasSize(1);
+ String message = result.get(0);
+ assertThat(message).isEqualTo("Technical Debt changed to 1 days");
+ }
+
+ @Test
+ public void format_technical_debt_without_value(){
+ FieldDiffs diffs = new FieldDiffs();
+ diffs.setDiff("technicalDebt", null, null);
+
+ when(i18nManager.message(DEFAULT_LOCALE, "issue.changelog.field.technicalDebt", null)).thenReturn("Technical Debt");
+ when(i18nManager.message(DEFAULT_LOCALE, "issue.changelog.removed", null, "Technical Debt")).thenReturn("Technical Debt removed");
+
+ List<String> result = formatter.format(DEFAULT_LOCALE, diffs);
+ assertThat(result).hasSize(1);
+ String message = result.get(0);
+ assertThat(message).isEqualTo("Technical Debt removed");
+ }
+
}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.server.technicaldebt;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.sonar.api.technicaldebt.TechnicalDebt;
+
+import java.util.Locale;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+
+@RunWith(MockitoJUnitRunner.class)
+public class InternalRubyTechnicalDebtServiceTest {
+
+ @Mock
+ private TechnicalDebtFormatter technicalDebtFormatter;
+
+ private InternalRubyTechnicalDebtService service;
+
+ @Before
+ public void before() {
+ service = new InternalRubyTechnicalDebtService(technicalDebtFormatter);
+ }
+
+ @Test
+ public void format() {
+ TechnicalDebt technicalDebt = TechnicalDebt.of(5, 0, 0);
+ service.format(technicalDebt);
+ verify(technicalDebtFormatter).format(any(Locale.class), eq(technicalDebt));
+ }
+
+ @Test
+ public void to_technical_debt() {
+ assertThat(service.toTechnicalDebt("500")).isEqualTo(TechnicalDebt.of(0, 5, 0));
+ }
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 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.server.technicaldebt;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.sonar.api.technicaldebt.TechnicalDebt;
+import org.sonar.core.i18n.I18nManager;
+
+import java.util.Locale;
+
+import static org.fest.assertions.Assertions.assertThat;
+import static org.mockito.Mockito.when;
+
+@RunWith(MockitoJUnitRunner.class)
+public class TechnicalDebtFormatterTest {
+
+ private static final Locale DEFAULT_LOCALE = Locale.getDefault();
+
+ @Mock
+ private I18nManager i18nManager;
+
+ private TechnicalDebtFormatter formatter;
+
+ @Before
+ public void before() {
+ formatter = new TechnicalDebtFormatter(i18nManager);
+ }
+
+ @Test
+ public void format() {
+ when(i18nManager.message(DEFAULT_LOCALE, "issue.technical_debt.x_days", null, 5)).thenReturn("5 days");
+ when(i18nManager.message(DEFAULT_LOCALE, "issue.technical_debt.x_hours", null, 2)).thenReturn("2 hours");
+ when(i18nManager.message(DEFAULT_LOCALE, "issue.technical_debt.x_minutes", null, 1)).thenReturn("1 minutes");
+
+ assertThat(formatter.format(DEFAULT_LOCALE, TechnicalDebt.of(0, 0, 5))).isEqualTo("5 days");
+ assertThat(formatter.format(DEFAULT_LOCALE, TechnicalDebt.of(0, 2, 0))).isEqualTo("2 hours");
+ assertThat(formatter.format(DEFAULT_LOCALE, TechnicalDebt.of(1, 0, 0))).isEqualTo("1 minutes");
+
+ assertThat(formatter.format(DEFAULT_LOCALE, TechnicalDebt.of(0, 2, 5))).isEqualTo("5 days 2 hours");
+ assertThat(formatter.format(DEFAULT_LOCALE, TechnicalDebt.of(1, 2, 0))).isEqualTo("2 hours 1 minutes");
+ assertThat(formatter.format(DEFAULT_LOCALE, TechnicalDebt.of(1, 2, 5))).isEqualTo("5 days 2 hours");
+ }
+
+
+}
package org.sonar.wsclient.issue.internal;
import org.apache.commons.io.IOUtils;
+import org.junit.Ignore;
import org.junit.Test;
import org.sonar.wsclient.base.Paging;
import org.sonar.wsclient.component.Component;
assertThat(diff2Change2.oldValue()).isEqualTo("RESOLVED");
}
+ @Test
+ @Ignore
+ public void should_parse_changelog_with_technical_debt() throws Exception {
+ String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/internal/IssueJsonParserTest/changelog-with-technical-debt.json"));
+ List<IssueChange> changes = new IssueJsonParser().parseChangelog(json);
+
+ assertThat(changes).hasSize(1);
+ IssueChange change = changes.get(0);
+ assertThat(change.user()).isEqualTo("julien");
+ assertThat(change.createdAt().getTime()).isEqualTo(1383202235000l);
+ assertThat(change.updatedAt().getTime()).isEqualTo(1383202235000l);
+
+ assertThat(change.diffs()).hasSize(1);
+ IssueChangeDiff diffChange1 = change.diffs().get(0);
+ assertThat(diffChange1.key()).isEqualTo("technicalDebt");
+ assertThat(diffChange1.newValue()).isEqualTo("1.0");
+ assertThat(diffChange1.oldValue()).isNull();
+ }
+
@Test
public void should_parse_bulk_change() throws Exception {
String json = IOUtils.toString(getClass().getResourceAsStream("/org/sonar/wsclient/issue/internal/IssueJsonParserTest/bulk-change.json"));
--- /dev/null
+{
+ "changelog": [
+ {
+ "user": "julien",
+ "createdAt": "2013-10-31T07:50:35+0100",
+ "updatedAt": "2013-10-31T07:50:35+0100",
+ "diffs": [
+ {
+ "key": "technicalDebt",
+ "oldValue": {
+ "days": 3,
+ "hours": 0,
+ "minutes": 10
+ },
+ "newValue": {
+ "days": 2,
+ "hours": 1,
+ "minutes": 0
+ }
+ }
+ ]
+ }
+ ]
+}
+