From: Julien Lancelot Date: Mon, 3 Mar 2014 10:49:18 +0000 (+0100) Subject: SONAR-4996 Update work duration message and move code to i18n API X-Git-Tag: 4.3~609 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=25ed28a254c799d17e7dd4ec55e171cd183e7ad3;p=sonarqube.git SONAR-4996 Update work duration message and move code to i18n API --- diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties b/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties index b5081cf1c54..723a04ccbfe 100644 --- a/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties +++ b/plugins/sonar-core-plugin/src/main/resources/org/sonar/l10n/core.properties @@ -249,12 +249,9 @@ since_previous_version.short=\u0394 version since_previous_version_detailed=since previous version ({0} - {1}) since_previous_version_detailed.short=\u0394 version ({0}) time_changes=Time changes -work_duration.x_days={0} days -work_duration.x_days.short={0}d -work_duration.x_hours={0} hours -work_duration.x_hours.short={0}h -work_duration.x_minutes={0} minutes -work_duration.x_minutes.short={0}min +work_duration.x_days={0}d +work_duration.x_hours={0}h +work_duration.x_minutes={0}min #------------------------------------------------------------------------------ # diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/issues/issues.html.erb b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/issues/issues.html.erb index 9b297d38804..db627c8cdd8 100644 --- a/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/issues/issues.html.erb +++ b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/issues/issues.html.erb @@ -71,7 +71,7 @@
<%= message('widget.rules.removed') -%>  - <%= Internal.work_duration_formatter.format(estimated_cleared_technical_debt, 'SHORT') -%> + <%= Internal.i18n.formatWorkDuration(estimated_cleared_technical_debt) -%> <% end %> <% end %> diff --git a/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/technical_debt_pyramid.html.erb b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/technical_debt_pyramid.html.erb index 8831a94def9..6ee8536cdfc 100644 --- a/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/technical_debt_pyramid.html.erb +++ b/plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/technical_debt_pyramid.html.erb @@ -115,7 +115,7 @@ - <%= Internal.work_duration_formatter.format(value.to_i, 'SHORT') -%> + <%= Internal.i18n.formatWorkDuration(value.to_i) -%> <% if should_display_diff_measures %> <% if diff_by_characteristic_id[characteristic.id] %> <%= format_variation(measure) -%> @@ -125,13 +125,13 @@ <% end %> - <%= Internal.work_duration_formatter.format(cumulated.to_i, 'SHORT') -%> + <%= Internal.i18n.formatWorkDuration(cumulated.to_i) -%> <% if should_display_diff_measures css_style = 'var' css_style += 'b' if total_diff < 0 css_style += 'w' if total_diff > 0 - diff_to_display = (total_diff < 0 ? '' : '+') + Internal.work_duration_formatter.format(total_diff.to_i, 'SHORT') + diff_to_display = (total_diff < 0 ? '' : '+') + Internal.i18n.formatWorkDuration(total_diff.to_i) %> (<%= diff_to_display -%>) <% diff --git a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java index a30a49bfb25..da73f5f7e95 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java +++ b/sonar-batch/src/main/java/org/sonar/batch/bootstrap/BootstrapContainer.java @@ -26,11 +26,13 @@ import org.sonar.api.platform.ComponentContainer; import org.sonar.api.platform.PluginMetadata; import org.sonar.api.utils.HttpDownloader; import org.sonar.api.utils.UriReader; +import org.sonar.api.utils.WorkDurationFactory; import org.sonar.api.utils.internal.TempFolderCleaner; import org.sonar.batch.components.*; import org.sonar.core.config.Logback; import org.sonar.core.i18n.DefaultI18n; import org.sonar.core.i18n.RuleI18nManager; +import org.sonar.core.i18n.WorkDurationFormatter; import org.sonar.core.metric.CacheMetricFinder; import org.sonar.core.persistence.*; import org.sonar.core.purge.PurgeProfiler; @@ -123,7 +125,10 @@ public class BootstrapContainer extends ComponentContainer { PastSnapshotFinderByVersion.class, PastSnapshotFinderByPreviousVersion.class, PastMeasuresLoader.class, - PastSnapshotFinder.class); + PastSnapshotFinder.class, + WorkDurationFormatter.class, + WorkDurationFactory.class + ); } @Override diff --git a/sonar-core/src/main/java/org/sonar/core/i18n/DefaultI18n.java b/sonar-core/src/main/java/org/sonar/core/i18n/DefaultI18n.java index abf12bc0890..8737323a147 100644 --- a/sonar-core/src/main/java/org/sonar/core/i18n/DefaultI18n.java +++ b/sonar-core/src/main/java/org/sonar/core/i18n/DefaultI18n.java @@ -43,9 +43,11 @@ import java.text.MessageFormat; import java.util.*; public class DefaultI18n implements I18n, ServerExtension, BatchExtension, Startable { + private static final Logger LOG = LoggerFactory.getLogger(DefaultI18n.class); public static final String BUNDLE_PACKAGE = "org.sonar.l10n."; + private final WorkDurationFormatter workDurationFormatter; private PluginRepository pluginRepository; private I18nClassloader i18nClassloader; @@ -53,13 +55,14 @@ public class DefaultI18n implements I18n, ServerExtension, BatchExtension, Start private final ResourceBundle.Control control; private final System2 system2; - public DefaultI18n(PluginRepository pluginRepository) { - this(pluginRepository, System2.INSTANCE); + public DefaultI18n(PluginRepository pluginRepository, WorkDurationFormatter workDurationFormatter) { + this(pluginRepository, workDurationFormatter, System2.INSTANCE); } @VisibleForTesting - DefaultI18n(PluginRepository pluginRepository, System2 system2) { + DefaultI18n(PluginRepository pluginRepository, WorkDurationFormatter workDurationFormatter, System2 system2) { this.pluginRepository = pluginRepository; + this.workDurationFormatter = workDurationFormatter; this.system2 = system2; // SONAR-2927 this.control = new ResourceBundle.Control() { @@ -144,6 +147,23 @@ public class DefaultI18n implements I18n, ServerExtension, BatchExtension, Start return DateFormat.getDateInstance(DateFormat.DEFAULT, locale).format(date); } + @Override + public String formatWorkDuration(Locale locale, long duration) { + if (duration == 0) { + return "0"; + } + List results = workDurationFormatter.format(duration); + StringBuilder message = new StringBuilder(); + for (WorkDurationFormatter.Result result : results) { + if (result.key().equals(" ")) { + message.append(" "); + } else { + message.append(message(locale, result.key(), null, result.value())); + } + } + return message.toString(); + } + /** * Only the given locale is searched. Contrary to java.util.ResourceBundle, no strategy for locating the bundle is implemented in * this method. diff --git a/sonar-core/src/main/java/org/sonar/core/i18n/WorkDurationFormatter.java b/sonar-core/src/main/java/org/sonar/core/i18n/WorkDurationFormatter.java new file mode 100644 index 00000000000..16e0713c5fa --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/i18n/WorkDurationFormatter.java @@ -0,0 +1,124 @@ +/* + * 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.core.i18n; + +import org.apache.commons.lang.builder.ReflectionToStringBuilder; +import org.apache.commons.lang.builder.ToStringStyle; +import org.sonar.api.BatchExtension; +import org.sonar.api.ServerComponent; +import org.sonar.api.utils.WorkDuration; +import org.sonar.api.utils.WorkDurationFactory; + +import javax.annotation.CheckForNull; + +import java.util.List; + +import static com.google.common.collect.Lists.newArrayList; + +public class WorkDurationFormatter implements ServerComponent, BatchExtension { + + private final WorkDurationFactory workDurationFactory; + + public WorkDurationFormatter(WorkDurationFactory workDurationFactory) { + this.workDurationFactory = workDurationFactory; + } + + public List format(long durationInSeconds) { + List results = newArrayList(); + if (durationInSeconds == 0) { + return newArrayList(new Result("0", null)); + } + boolean isNegative = durationInSeconds < 0; + Long absDuration = Math.abs(durationInSeconds); + WorkDuration workDuration = workDurationFactory.createFromMinutes(absDuration); + if (workDuration.days() > 0) { + results.add(message("work_duration.x_days", isNegative ? -1 * workDuration.days() : workDuration.days())); + } + if (workDuration.hours() > 0 && workDuration.days() < 10) { + if (!results.isEmpty()) { + results.add(new Result(" ", null)); + } + results.add(message("work_duration.x_hours", isNegative && results.isEmpty() ? -1 * workDuration.hours() : workDuration.hours())); + } + if (workDuration.minutes() > 0 && workDuration.hours() < 10 && workDuration.days() == 0) { + if (!results.isEmpty()) { + results.add(new Result(" ", null)); + } + results.add(message("work_duration.x_minutes", isNegative && results.isEmpty() ? -1 * workDuration.minutes() : workDuration.minutes())); + } + return results; + } + + private Result message(String key, @CheckForNull Object parameter) { + return new Result(key, parameter); + } + + static class Result { + private String key; + private Object value; + + Result(String key, Object value) { + this.key = key; + this.value = value; + } + + String key() { + return key; + } + + Object value() { + return value; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Result result = (Result) o; + + if (key != null ? !key.equals(result.key) : result.key != null) { + return false; + } + if (value != null ? !value.equals(result.value) : result.value != null) { + return false; + } + + return true; + } + + @Override + public int hashCode() { + int result = key != null ? key.hashCode() : 0; + result = 31 * result + (value != null ? value.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return new ReflectionToStringBuilder(this, ToStringStyle.SIMPLE_STYLE).toString(); + } + } +} diff --git a/sonar-core/src/test/java/org/sonar/core/i18n/DefaultI18nTest.java b/sonar-core/src/test/java/org/sonar/core/i18n/DefaultI18nTest.java index 3c5bc0d6d48..f225a1b0e40 100644 --- a/sonar-core/src/test/java/org/sonar/core/i18n/DefaultI18nTest.java +++ b/sonar-core/src/test/java/org/sonar/core/i18n/DefaultI18nTest.java @@ -35,6 +35,7 @@ import java.util.Arrays; import java.util.List; import java.util.Locale; +import static com.google.common.collect.Lists.newArrayList; import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -45,6 +46,10 @@ public class DefaultI18nTest { @Mock System2 system2; + @Mock + WorkDurationFormatter workDurationFormatter; + + DefaultI18n manager; @Before @@ -56,7 +61,7 @@ public class DefaultI18nTest { I18nClassloader i18nClassloader = new I18nClassloader(new ClassLoader[]{ newCoreClassloader(), newFrenchPackClassloader(), newSqaleClassloader(), newCheckstyleClassloader() }); - manager = new DefaultI18n(pluginRepository, system2); + manager = new DefaultI18n(pluginRepository, workDurationFormatter, system2); manager.doStart(i18nClassloader); } @@ -194,6 +199,23 @@ public class DefaultI18nTest { assertThat(manager.formatDate(Locale.ENGLISH, DateUtils.parseDate("2014-01-22"))).isEqualTo("Jan 22, 2014"); } + @Test + public void format_work_duration() { + when(workDurationFormatter.format(10)).thenReturn(newArrayList( + new WorkDurationFormatter.Result("work_duration.x_days", 5), + new WorkDurationFormatter.Result(" ", null), + new WorkDurationFormatter.Result("work_duration.x_hours", 2), + new WorkDurationFormatter.Result(" ", null), + new WorkDurationFormatter.Result("work_duration.x_minutes", 1) + )); + assertThat(manager.formatWorkDuration(Locale.ENGLISH, 10)).isEqualTo("5d 2h 1min"); + } + + @Test + public void format_work_duration_when_0() { + assertThat(manager.formatWorkDuration(Locale.ENGLISH, 0)).isEqualTo("0"); + } + static URLClassLoader newCoreClassloader() { return newClassLoader("/org/sonar/core/i18n/corePlugin/"); } diff --git a/sonar-core/src/test/java/org/sonar/core/i18n/WorkDurationFormatterTest.java b/sonar-core/src/test/java/org/sonar/core/i18n/WorkDurationFormatterTest.java new file mode 100644 index 00000000000..5185afd4d4c --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/i18n/WorkDurationFormatterTest.java @@ -0,0 +1,98 @@ +/* + * 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.core.i18n; + +import org.junit.Before; +import org.junit.Test; +import org.sonar.api.CoreProperties; +import org.sonar.api.config.Settings; +import org.sonar.api.utils.WorkDurationFactory; + +import static com.google.common.collect.Lists.newArrayList; +import static org.fest.assertions.Assertions.assertThat; + +public class WorkDurationFormatterTest { + + static final int HOURS_IN_DAY = 8; + + static final long ONE_MINUTE = 1L; + static final long ONE_HOUR = ONE_MINUTE * 60; + static final long ONE_DAY = HOURS_IN_DAY * ONE_HOUR; + + Settings settings; + + WorkDurationFormatter formatter; + + @Before + public void setUp() throws Exception { + settings = new Settings(); + settings.setProperty(CoreProperties.HOURS_IN_DAY, Integer.toString(HOURS_IN_DAY)); + formatter = new WorkDurationFormatter(new WorkDurationFactory(settings)); + } + + @Test + public void format() { + assertThat(formatter.format(5 * ONE_DAY)).isEqualTo(newArrayList(new WorkDurationFormatter.Result("work_duration.x_days", 5))); + assertThat(formatter.format(2 * ONE_HOUR)).isEqualTo(newArrayList(new WorkDurationFormatter.Result("work_duration.x_hours", 2))); + assertThat(formatter.format(ONE_MINUTE)).isEqualTo(newArrayList(new WorkDurationFormatter.Result("work_duration.x_minutes", 1))); + + assertThat(formatter.format(5 * ONE_DAY + 2 * ONE_HOUR)).isEqualTo(newArrayList( + new WorkDurationFormatter.Result("work_duration.x_days", 5), + new WorkDurationFormatter.Result(" ", null), + new WorkDurationFormatter.Result("work_duration.x_hours", 2) + )); + + assertThat(formatter.format(2 * ONE_HOUR + ONE_MINUTE)).isEqualTo(newArrayList( + new WorkDurationFormatter.Result("work_duration.x_hours", 2), + new WorkDurationFormatter.Result(" ", null), + new WorkDurationFormatter.Result("work_duration.x_minutes", 1) + )); + + assertThat(formatter.format(5 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE)).isEqualTo(newArrayList( + new WorkDurationFormatter.Result("work_duration.x_days", 5), + new WorkDurationFormatter.Result(" ", null), + new WorkDurationFormatter.Result("work_duration.x_hours", 2) + )); + } + + @Test + public void not_display_following_element_when_bigger_than_ten() { + int hoursInDay = 15; + settings.setProperty(CoreProperties.HOURS_IN_DAY, Integer.toString(hoursInDay)); + + assertThat(formatter.format(15 * hoursInDay * ONE_HOUR + 2 * ONE_HOUR + ONE_MINUTE)).isEqualTo(newArrayList(new WorkDurationFormatter.Result("work_duration.x_days", 15))); + + assertThat(formatter.format(12 * ONE_HOUR + ONE_MINUTE)).isEqualTo(newArrayList(new WorkDurationFormatter.Result("work_duration.x_hours", 12))); + } + + @Test + public void display_zero_without_unit() { + assertThat(formatter.format(0)).isEqualTo(newArrayList(new WorkDurationFormatter.Result("0", null))); + } + + @Test + public void display_negative_duration() { + assertThat(formatter.format(-5 * ONE_DAY)).isEqualTo(newArrayList(new WorkDurationFormatter.Result("work_duration.x_days", -5))); + assertThat(formatter.format(-2 * ONE_HOUR)).isEqualTo(newArrayList(new WorkDurationFormatter.Result("work_duration.x_hours", -2))); + assertThat(formatter.format(-1 * ONE_MINUTE)).isEqualTo(newArrayList(new WorkDurationFormatter.Result("work_duration.x_minutes", -1))); + } + +} diff --git a/sonar-core/src/test/resources/org/sonar/core/i18n/corePlugin/org/sonar/l10n/core.properties b/sonar-core/src/test/resources/org/sonar/core/i18n/corePlugin/org/sonar/l10n/core.properties index 4c8b337a136..d185db89e91 100644 --- a/sonar-core/src/test/resources/org/sonar/core/i18n/corePlugin/org/sonar/l10n/core.properties +++ b/sonar-core/src/test/resources/org/sonar/core/i18n/corePlugin/org/sonar/l10n/core.properties @@ -4,3 +4,6 @@ with.parameters=First is {0} and second is {1} only.in.english=Missing in French bundle duration.seconds=less than a minute duration.day=a day +work_duration.x_days={0}d +work_duration.x_hours={0}h +work_duration.x_minutes={0}min diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/i18n/I18n.java b/sonar-plugin-api/src/main/java/org/sonar/api/i18n/I18n.java index 7c7bdd3495f..c11356bd7c0 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/i18n/I18n.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/i18n/I18n.java @@ -102,4 +102,13 @@ public interface I18n extends ServerComponent, BatchComponent { */ String formatDate(Locale locale, Date date); + /** + * Return the formatted work duration. + *
+ * Example : format(Locale.ENGLISH, WorkDuration.create(10, 2, 0, 8)) -> 10d 2h + * + * @since 4.3 + */ + String formatWorkDuration(Locale locale, long duration); + } diff --git a/sonar-server/src/main/java/org/sonar/server/issue/IssueChangelogFormatter.java b/sonar-server/src/main/java/org/sonar/server/issue/IssueChangelogFormatter.java index 84e7d6bad20..fde05c3068f 100644 --- a/sonar-server/src/main/java/org/sonar/server/issue/IssueChangelogFormatter.java +++ b/sonar-server/src/main/java/org/sonar/server/issue/IssueChangelogFormatter.java @@ -20,10 +20,10 @@ package org.sonar.server.issue; import org.sonar.api.ServerComponent; +import org.sonar.api.i18n.I18n; import org.sonar.api.issue.internal.FieldDiffs; -import org.sonar.core.i18n.DefaultI18n; import org.sonar.core.issue.IssueUpdater; -import org.sonar.server.ui.WorkDurationFormatter; +import org.sonar.server.user.UserSession; import java.io.Serializable; import java.util.List; @@ -36,12 +36,10 @@ public class IssueChangelogFormatter implements ServerComponent { private static final String ISSUE_CHANGELOG_FIELD = "issue.changelog.field."; - private final DefaultI18n defaultI18n; - private final WorkDurationFormatter workDurationFormatter; + private final I18n i18n; - public IssueChangelogFormatter(DefaultI18n defaultI18n, WorkDurationFormatter workDurationFormatter) { - this.defaultI18n = defaultI18n; - this.workDurationFormatter = workDurationFormatter; + public IssueChangelogFormatter(I18n i18n) { + this.i18n = i18n; } public List format(Locale locale, FieldDiffs diffs) { @@ -51,13 +49,13 @@ public class IssueChangelogFormatter implements ServerComponent { String key = entry.getKey(); IssueChangelogDiffFormat diffFormat = format(locale, key, entry.getValue()); if (diffFormat.newValue() != null) { - message.append(defaultI18n.message(locale, "issue.changelog.changed_to", null, defaultI18n.message(locale, ISSUE_CHANGELOG_FIELD + key, null), diffFormat.newValue())); + message.append(i18n.message(locale, "issue.changelog.changed_to", null, i18n.message(locale, ISSUE_CHANGELOG_FIELD + key, null), diffFormat.newValue())); } else { - message.append(defaultI18n.message(locale, "issue.changelog.removed", null, defaultI18n.message(locale, ISSUE_CHANGELOG_FIELD + key, null))); + message.append(i18n.message(locale, "issue.changelog.removed", null, i18n.message(locale, ISSUE_CHANGELOG_FIELD + key, null))); } if (diffFormat.oldValue() != null) { message.append(" ("); - message.append(defaultI18n.message(locale, "issue.changelog.was", null, diffFormat.oldValue())); + message.append(i18n.message(locale, "issue.changelog.was", null, diffFormat.oldValue())); message.append(")"); } result.add(message.toString()); @@ -73,10 +71,11 @@ public class IssueChangelogFormatter implements ServerComponent { String oldValueString = oldValue != null && !"".equals(oldValue) ? oldValue.toString() : null; if (IssueUpdater.TECHNICAL_DEBT.equals(key)) { if (newValueString != null) { - newValueString = workDurationFormatter.format(Long.parseLong(newValueString), WorkDurationFormatter.Format.SHORT); + newValueString = i18n.formatWorkDuration(UserSession.get().locale(), Long.parseLong(newValueString)); } if (oldValueString != null) { - oldValueString = workDurationFormatter.format(Long.parseLong(oldValueString), WorkDurationFormatter.Format.SHORT); + // TODO use i18n API + oldValueString = i18n.formatWorkDuration(UserSession.get().locale(), Long.parseLong(oldValueString)); } } return new IssueChangelogDiffFormat(oldValueString, newValueString); diff --git a/sonar-server/src/main/java/org/sonar/server/issue/ws/IssueShowWsHandler.java b/sonar-server/src/main/java/org/sonar/server/issue/ws/IssueShowWsHandler.java index f74135f2e72..dcf82862e1d 100644 --- a/sonar-server/src/main/java/org/sonar/server/issue/ws/IssueShowWsHandler.java +++ b/sonar-server/src/main/java/org/sonar/server/issue/ws/IssueShowWsHandler.java @@ -44,7 +44,6 @@ import org.sonar.server.issue.ActionService; import org.sonar.server.issue.IssueChangelog; import org.sonar.server.issue.IssueChangelogService; import org.sonar.server.issue.IssueService; -import org.sonar.server.ui.WorkDurationFormatter; import org.sonar.server.user.UserSession; import javax.annotation.CheckForNull; @@ -62,17 +61,15 @@ public class IssueShowWsHandler implements RequestHandler { private final IssueService issueService; private final IssueChangelogService issueChangelogService; private final ActionService actionService; - private final WorkDurationFormatter workDurationFormatter; private final DefaultTechnicalDebtManager technicalDebtManager; private final I18n i18n; public IssueShowWsHandler(IssueFinder issueFinder, IssueService issueService, IssueChangelogService issueChangelogService, ActionService actionService, - WorkDurationFormatter workDurationFormatter, DefaultTechnicalDebtManager technicalDebtManager, I18n i18n) { + DefaultTechnicalDebtManager technicalDebtManager, I18n i18n) { this.issueFinder = issueFinder; this.issueService = issueService; this.issueChangelogService = issueChangelogService; this.actionService = actionService; - this.workDurationFormatter = workDurationFormatter; this.technicalDebtManager = technicalDebtManager; this.i18n = i18n; } @@ -129,7 +126,7 @@ public class IssueShowWsHandler implements RequestHandler { .prop("author", issue.authorLogin()) .prop("actionPlan", actionPlanKey) .prop("actionPlanName", actionPlan != null ? actionPlan.name() : null) - .prop("debt", technicalDebt != null ? workDurationFormatter.format(technicalDebt, WorkDurationFormatter.Format.SHORT) : null) + .prop("debt", technicalDebt != null ? i18n.formatWorkDuration(UserSession.get().locale(), technicalDebt) : null) .prop("creationDate", DateUtils.formatDateTime(issue.creationDate())) .prop("fCreationDate", formatDate(issue.creationDate())) .prop("updateDate", updateDate != null ? DateUtils.formatDateTime(updateDate) : null) diff --git a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java index 916e9f1f784..9417925697a 100644 --- a/sonar-server/src/main/java/org/sonar/server/platform/Platform.java +++ b/sonar-server/src/main/java/org/sonar/server/platform/Platform.java @@ -43,6 +43,7 @@ import org.sonar.core.config.Logback; import org.sonar.core.i18n.DefaultI18n; import org.sonar.core.i18n.GwtI18n; import org.sonar.core.i18n.RuleI18nManager; +import org.sonar.core.i18n.WorkDurationFormatter; import org.sonar.core.issue.IssueFilterSerializer; import org.sonar.core.issue.IssueNotifications; import org.sonar.core.issue.IssueUpdater; @@ -115,7 +116,10 @@ import org.sonar.server.startup.*; import org.sonar.server.technicaldebt.DebtService; import org.sonar.server.text.MacroInterpreter; import org.sonar.server.text.RubyTextService; -import org.sonar.server.ui.*; +import org.sonar.server.ui.JRubyI18n; +import org.sonar.server.ui.JRubyProfiling; +import org.sonar.server.ui.PageDecorations; +import org.sonar.server.ui.Views; import org.sonar.server.user.*; import org.sonar.server.util.*; import org.sonar.server.ws.ListingWs; @@ -216,6 +220,9 @@ public final class Platform { rootContainer.addSingleton(DefaultI18n.class); rootContainer.addSingleton(RuleI18nManager.class); rootContainer.addSingleton(GwtI18n.class); + rootContainer.addSingleton(WorkDurationFormatter.class); + rootContainer.addSingleton(WorkDurationFactory.class); + rootContainer.addSingleton(PreviewDatabaseFactory.class); rootContainer.addSingleton(SemaphoreUpdater.class); rootContainer.addSingleton(SemaphoresImpl.class); @@ -381,9 +388,7 @@ public final class Platform { servicesContainer.addSingleton(TechnicalDebtModelSynchronizer.class); servicesContainer.addSingleton(TechnicalDebtModelRepository.class); servicesContainer.addSingleton(TechnicalDebtXMLImporter.class); - servicesContainer.addSingleton(WorkDurationFormatter.class); servicesContainer.addSingleton(DefaultTechnicalDebtManager.class); - servicesContainer.addSingleton(WorkDurationFactory.class); // source servicesContainer.addSingleton(HtmlSourceDecorator.class); diff --git a/sonar-server/src/main/java/org/sonar/server/technicaldebt/DebtService.java b/sonar-server/src/main/java/org/sonar/server/technicaldebt/DebtService.java index f473dd0e7b0..540193cd19f 100644 --- a/sonar-server/src/main/java/org/sonar/server/technicaldebt/DebtService.java +++ b/sonar-server/src/main/java/org/sonar/server/technicaldebt/DebtService.java @@ -25,27 +25,21 @@ import org.sonar.api.technicaldebt.server.Characteristic; import org.sonar.api.utils.WorkDuration; import org.sonar.api.utils.WorkDurationFactory; import org.sonar.core.technicaldebt.DefaultTechnicalDebtManager; -import org.sonar.server.ui.WorkDurationFormatter; import javax.annotation.CheckForNull; + import java.util.List; public class DebtService implements ServerComponent { - private final WorkDurationFormatter workDurationFormatter; private final DefaultTechnicalDebtManager finder; private final WorkDurationFactory workDurationFactory; - public DebtService(WorkDurationFormatter workDurationFormatter, DefaultTechnicalDebtManager finder, WorkDurationFactory workDurationFactory) { - this.workDurationFormatter = workDurationFormatter; + public DebtService(DefaultTechnicalDebtManager finder, WorkDurationFactory workDurationFactory) { this.finder = finder; this.workDurationFactory = workDurationFactory; } - public String format(long debt) { - return workDurationFormatter.format(debt, WorkDurationFormatter.Format.SHORT); - } - public WorkDuration toWorkDuration(long debt) { return workDurationFactory.createFromMinutes(debt); } diff --git a/sonar-server/src/main/java/org/sonar/server/ui/JRubyI18n.java b/sonar-server/src/main/java/org/sonar/server/ui/JRubyI18n.java index fc5b66bcb42..3931567b6fb 100644 --- a/sonar-server/src/main/java/org/sonar/server/ui/JRubyI18n.java +++ b/sonar-server/src/main/java/org/sonar/server/ui/JRubyI18n.java @@ -86,4 +86,8 @@ public class JRubyI18n implements ServerComponent { return i18n.ageFromNow(UserSession.get().locale(), date); } + public String formatWorkDuration(long duration) { + return i18n.formatWorkDuration(UserSession.get().locale(), duration); + } + } diff --git a/sonar-server/src/main/java/org/sonar/server/ui/WorkDurationFormatter.java b/sonar-server/src/main/java/org/sonar/server/ui/WorkDurationFormatter.java deleted file mode 100644 index d070abd5b0f..00000000000 --- a/sonar-server/src/main/java/org/sonar/server/ui/WorkDurationFormatter.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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.ui; - -import org.sonar.api.ServerComponent; -import org.sonar.api.utils.WorkDuration; -import org.sonar.api.utils.WorkDurationFactory; -import org.sonar.core.i18n.DefaultI18n; -import org.sonar.server.user.UserSession; - -import java.util.Locale; - -public class WorkDurationFormatter implements ServerComponent { - - public enum Format { - SHORT, LONG - } - - private final DefaultI18n defaultI18n; - private final WorkDurationFactory workDurationFactory; - - public WorkDurationFormatter(DefaultI18n defaultI18n, WorkDurationFactory workDurationFactory) { - this.defaultI18n = defaultI18n; - this.workDurationFactory = workDurationFactory; - } - - /** - * Used by rails - */ - public String format(long durationInSeconds, String stringFormat) { - return format(durationInSeconds, Format.valueOf(stringFormat)); - } - - public String format(long durationInSeconds, Format format) { - return formatWorkDuration(UserSession.get().locale(), durationInSeconds, format); - } - - private String formatWorkDuration(Locale locale, long durationInSeconds, Format format) { - if (durationInSeconds == 0) { - return "0"; - } - Long absDuration = Math.abs(durationInSeconds); - WorkDuration workDuration = workDurationFactory.createFromMinutes(absDuration); - boolean shortLabel = Format.SHORT.equals(format); - StringBuilder message = new StringBuilder(); - if (workDuration.days() > 0) { - message.append(message(locale, "work_duration.x_days", shortLabel, workDuration.days())); - } - if (workDuration.hours() > 0) { - if (message.length() > 0) { - message.append(" "); - } - message.append(message(locale, "work_duration.x_hours", shortLabel, workDuration.hours())); - } - if (workDuration.minutes() > 0) { - if (message.length() > 0) { - message.append(" "); - } - message.append(message(locale, "work_duration.x_minutes", shortLabel, workDuration.minutes())); - } - if (durationInSeconds < 0) { - message.insert(0, "-"); - } - return message.toString(); - } - - private String message(Locale locale, String key, boolean shortLabel, Object... parameters) { - String msgKey = key; - if (shortLabel) { - msgKey += ".short"; - } - return defaultI18n.message(locale, msgKey, null, parameters); - } -} diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/internal.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/internal.rb index a8961cac95f..b169243bb19 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/internal.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/internal.rb @@ -90,10 +90,6 @@ class Internal component(Java::OrgSonarServerUi::JRubyI18n.java_class) end - def self.work_duration_formatter - component(Java::OrgSonarServerUi::WorkDurationFormatter.java_class) - end - private def self.component(component_java_class) diff --git a/sonar-server/src/main/webapp/WEB-INF/app/models/project_measure.rb b/sonar-server/src/main/webapp/WEB-INF/app/models/project_measure.rb index 096cc08c203..f600e43430d 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/models/project_measure.rb +++ b/sonar-server/src/main/webapp/WEB-INF/app/models/project_measure.rb @@ -164,7 +164,7 @@ class ProjectMeasure < ActiveRecord::Base end def work_duration_formatted_value(value) - Internal.work_duration_formatter.format(value.to_i, 'SHORT') + Internal.i18n.formatWorkDuration(value.to_i) end def color diff --git a/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_issue.html.erb b/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_issue.html.erb index efd6b582ccc..304bf918f5b 100644 --- a/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_issue.html.erb +++ b/sonar-server/src/main/webapp/WEB-INF/app/views/issue/_issue.html.erb @@ -96,7 +96,7 @@ <% end %> <% end %> <% if issue.debt %> -
  • <%= message('issue.debt') -%> <%= Internal.technical_debt.format(issue.debt) -%>
  • +
  • <%= message('issue.debt') -%> <%= Internal.i18n.formatWorkDuration(issue.debt) -%>
  • <% end %> <% if issue.authorLogin %>
  • <%= message('issue.authorLogin') -%> <%= issue.authorLogin -%>
  • diff --git a/sonar-server/src/test/java/org/sonar/server/issue/IssueChangelogFormatterTest.java b/sonar-server/src/test/java/org/sonar/server/issue/IssueChangelogFormatterTest.java index 42ce6868862..1dcb81c46c7 100644 --- a/sonar-server/src/test/java/org/sonar/server/issue/IssueChangelogFormatterTest.java +++ b/sonar-server/src/test/java/org/sonar/server/issue/IssueChangelogFormatterTest.java @@ -24,14 +24,15 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; +import org.sonar.api.i18n.I18n; import org.sonar.api.issue.internal.FieldDiffs; -import org.sonar.core.i18n.DefaultI18n; -import org.sonar.server.ui.WorkDurationFormatter; import java.util.List; 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.when; @RunWith(MockitoJUnitRunner.class) @@ -39,19 +40,14 @@ public class IssueChangelogFormatterTest { private static final Locale DEFAULT_LOCALE = Locale.getDefault(); - private static final int HOURS_IN_DAY = 8; - - @Mock - private DefaultI18n i18n; - @Mock - private WorkDurationFormatter workDurationFormatter; + private I18n i18n; private IssueChangelogFormatter formatter; @Before public void before() { - formatter = new IssueChangelogFormatter(i18n, workDurationFormatter); + formatter = new IssueChangelogFormatter(i18n); } @Test @@ -131,8 +127,8 @@ public class IssueChangelogFormatterTest { FieldDiffs diffs = new FieldDiffs(); diffs.setDiff("technicalDebt", "18000", "28800"); - when(workDurationFormatter.format(18000, WorkDurationFormatter.Format.SHORT)).thenReturn("5 hours"); - when(workDurationFormatter.format(28800, WorkDurationFormatter.Format.SHORT)).thenReturn("1 days"); + when(i18n.formatWorkDuration(any(Locale.class), eq(18000L))).thenReturn("5 hours"); + when(i18n.formatWorkDuration(any(Locale.class), eq(28800L))).thenReturn("1 days"); when(i18n.message(DEFAULT_LOCALE, "issue.changelog.field.technicalDebt", null)).thenReturn("Technical Debt"); when(i18n.message(DEFAULT_LOCALE, "issue.changelog.changed_to", null, "Technical Debt", "1 days")).thenReturn("Technical Debt changed to 1 days"); @@ -149,7 +145,7 @@ public class IssueChangelogFormatterTest { FieldDiffs diffs = new FieldDiffs(); diffs.setDiff("technicalDebt", null, "28800"); - when(workDurationFormatter.format(28800, WorkDurationFormatter.Format.SHORT)).thenReturn("1 days"); + when(i18n.formatWorkDuration(any(Locale.class), eq(28800L))).thenReturn("1 days"); when(i18n.message(DEFAULT_LOCALE, "issue.changelog.field.technicalDebt", null)).thenReturn("Technical Debt"); when(i18n.message(DEFAULT_LOCALE, "issue.changelog.changed_to", null, "Technical Debt", "1 days")).thenReturn("Technical Debt changed to 1 days"); diff --git a/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueShowWsHandlerTest.java b/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueShowWsHandlerTest.java index 174e1e65ef0..a17a9069587 100644 --- a/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueShowWsHandlerTest.java +++ b/sonar-server/src/test/java/org/sonar/server/issue/ws/IssueShowWsHandlerTest.java @@ -53,7 +53,6 @@ import org.sonar.server.issue.ActionService; import org.sonar.server.issue.IssueChangelog; import org.sonar.server.issue.IssueChangelogService; import org.sonar.server.issue.IssueService; -import org.sonar.server.ui.WorkDurationFormatter; import org.sonar.server.user.MockUserSession; import org.sonar.server.user.UserSession; @@ -83,9 +82,6 @@ public class IssueShowWsHandlerTest { @Mock ActionService actionService; - @Mock - WorkDurationFormatter workDurationFormatter; - @Mock DefaultTechnicalDebtManager technicalDebtManager; @@ -113,7 +109,7 @@ public class IssueShowWsHandlerTest { when(i18n.message(any(Locale.class), eq("created"), eq((String) null))).thenReturn("Created"); - tester = new WsTester(new IssuesWs(new IssueShowWsHandler(issueFinder, issueService, issueChangelogService, actionService, workDurationFormatter, technicalDebtManager, i18n))); + tester = new WsTester(new IssuesWs(new IssueShowWsHandler(issueFinder, issueService, issueChangelogService, actionService, technicalDebtManager, i18n))); } @Test @@ -264,7 +260,7 @@ public class IssueShowWsHandlerTest { Issue issue = createStandardIssue().setDebt(technicalDebt); issues.add(issue); - when(workDurationFormatter.format(eq(technicalDebt), any(WorkDurationFormatter.Format.class))).thenReturn("2 hours 1 minutes"); + when(i18n.formatWorkDuration(any(Locale.class), eq(technicalDebt))).thenReturn("2 hours 1 minutes"); MockUserSession.set(); WsTester.TestRequest request = tester.newRequest("show").setParam("key", issue.key()); diff --git a/sonar-server/src/test/java/org/sonar/server/technicaldebt/DebtServiceTest.java b/sonar-server/src/test/java/org/sonar/server/technicaldebt/DebtServiceTest.java index 9e29013e887..d5292636a74 100644 --- a/sonar-server/src/test/java/org/sonar/server/technicaldebt/DebtServiceTest.java +++ b/sonar-server/src/test/java/org/sonar/server/technicaldebt/DebtServiceTest.java @@ -28,19 +28,16 @@ import org.sonar.api.technicaldebt.server.internal.DefaultCharacteristic; import org.sonar.api.utils.WorkDuration; import org.sonar.api.utils.WorkDurationFactory; import org.sonar.core.technicaldebt.DefaultTechnicalDebtManager; -import org.sonar.server.ui.WorkDurationFormatter; import java.util.List; import static com.google.common.collect.Lists.newArrayList; import static org.fest.assertions.Assertions.assertThat; -import static org.mockito.Matchers.eq; import static org.mockito.Mockito.*; public class DebtServiceTest { private static final int HOURS_IN_DAY = 8; - WorkDurationFormatter workDurationFormatter = mock(WorkDurationFormatter.class); DefaultTechnicalDebtManager finder = mock(DefaultTechnicalDebtManager.class); DebtService service; @@ -49,13 +46,7 @@ public class DebtServiceTest { public void setUp() throws Exception { Settings settings = new Settings(); settings.setProperty(CoreProperties.HOURS_IN_DAY, HOURS_IN_DAY); - service = new DebtService(workDurationFormatter, finder, new WorkDurationFactory(settings)); - } - - @Test - public void format() { - service.format(10L); - verify(workDurationFormatter).format(eq(10L), eq(WorkDurationFormatter.Format.SHORT)); + service = new DebtService(finder, new WorkDurationFactory(settings)); } @Test diff --git a/sonar-server/src/test/java/org/sonar/server/ui/JRubyI18nTest.java b/sonar-server/src/test/java/org/sonar/server/ui/JRubyI18nTest.java index 031be00e869..1060704e119 100644 --- a/sonar-server/src/test/java/org/sonar/server/ui/JRubyI18nTest.java +++ b/sonar-server/src/test/java/org/sonar/server/ui/JRubyI18nTest.java @@ -92,4 +92,10 @@ public class JRubyI18nTest { verify(i18n).ageFromNow(any(Locale.class), eq(date)); } + @Test + public void format_work_duration() throws Exception { + jRubyI18n.formatWorkDuration(10L); + verify(i18n).formatWorkDuration(any(Locale.class), eq(10L)); + } + } diff --git a/sonar-server/src/test/java/org/sonar/server/ui/WorkDurationFormatterTest.java b/sonar-server/src/test/java/org/sonar/server/ui/WorkDurationFormatterTest.java deleted file mode 100644 index a973425e1e5..00000000000 --- a/sonar-server/src/test/java/org/sonar/server/ui/WorkDurationFormatterTest.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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.ui; - -import org.junit.Before; -import org.junit.Test; -import org.sonar.api.CoreProperties; -import org.sonar.api.config.Settings; -import org.sonar.api.utils.WorkDurationFactory; -import org.sonar.core.i18n.DefaultI18n; - -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.mock; -import static org.mockito.Mockito.when; - -public class WorkDurationFormatterTest { - - static final int HOURS_IN_DAY = 8; - - static final long ONE_MINUTE = 1L; - static final long ONE_HOUR = ONE_MINUTE * 60; - static final long ONE_DAY = HOURS_IN_DAY * ONE_HOUR; - - DefaultI18n i18n = mock(DefaultI18n.class); - WorkDurationFormatter formatter; - - @Before - public void setUp() throws Exception { - Settings settings = new Settings(); - settings.setProperty(CoreProperties.HOURS_IN_DAY, Integer.toString(HOURS_IN_DAY)); - formatter = new WorkDurationFormatter(i18n, new WorkDurationFactory(settings)); - - when(i18n.message(any(Locale.class), eq("work_duration.x_days"), eq((String) null), eq(5))).thenReturn("5 days"); - when(i18n.message(any(Locale.class), eq("work_duration.x_days.short"), eq((String) null), eq(5))).thenReturn("5d"); - when(i18n.message(any(Locale.class), eq("work_duration.x_hours"), eq((String) null), eq(2))).thenReturn("2 hours"); - when(i18n.message(any(Locale.class), eq("work_duration.x_hours.short"), eq((String) null), eq(2))).thenReturn("2h"); - when(i18n.message(any(Locale.class), eq("work_duration.x_minutes"), eq((String) null), eq(1))).thenReturn("1 minutes"); - when(i18n.message(any(Locale.class), eq("work_duration.x_minutes.short"), eq((String) null), eq(1))).thenReturn("1min"); - } - - @Test - public void long_format() { - assertThat(formatter.format(5 * ONE_DAY, WorkDurationFormatter.Format.LONG)).isEqualTo("5 days"); - assertThat(formatter.format(2 * ONE_HOUR, WorkDurationFormatter.Format.LONG)).isEqualTo("2 hours"); - assertThat(formatter.format(ONE_MINUTE, WorkDurationFormatter.Format.LONG)).isEqualTo("1 minutes"); - - assertThat(formatter.format(5 * ONE_DAY + 2 * ONE_HOUR, WorkDurationFormatter.Format.LONG)).isEqualTo("5 days 2 hours"); - assertThat(formatter.format(2 * ONE_HOUR + ONE_MINUTE, WorkDurationFormatter.Format.LONG)).isEqualTo("2 hours 1 minutes"); - - assertThat(formatter.format(5 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE, WorkDurationFormatter.Format.LONG)).isEqualTo("5 days 2 hours 1 minutes"); - } - - @Test - public void short_format() { - assertThat(formatter.format(5 * ONE_DAY, WorkDurationFormatter.Format.SHORT)).isEqualTo("5d"); - assertThat(formatter.format(2 * ONE_HOUR, WorkDurationFormatter.Format.SHORT)).isEqualTo("2h"); - assertThat(formatter.format(ONE_MINUTE, WorkDurationFormatter.Format.SHORT)).isEqualTo("1min"); - - assertThat(formatter.format(5 * ONE_DAY + 2 * ONE_HOUR, WorkDurationFormatter.Format.SHORT)).isEqualTo("5d 2h"); - assertThat(formatter.format(2 * ONE_HOUR + ONE_MINUTE, WorkDurationFormatter.Format.SHORT)).isEqualTo("2h 1min"); - - assertThat(formatter.format(5 * ONE_DAY + 2 * ONE_HOUR + ONE_MINUTE, WorkDurationFormatter.Format.SHORT)).isEqualTo("5d 2h 1min"); - } - - @Test - public void format_with_string_parameter() { - assertThat(formatter.format(5 * ONE_DAY, "LONG")).isEqualTo("5 days"); - assertThat(formatter.format(5 * ONE_DAY, "SHORT")).isEqualTo("5d"); - } - - @Test - public void display_zero_without_unit() { - assertThat(formatter.format(0, WorkDurationFormatter.Format.SHORT)).isEqualTo("0"); - } - - @Test - public void display_negative_duration() { - assertThat(formatter.format(-5 * ONE_DAY, WorkDurationFormatter.Format.SHORT)).isEqualTo("-5d"); - assertThat(formatter.format(-2 * ONE_HOUR, WorkDurationFormatter.Format.SHORT)).isEqualTo("-2h"); - assertThat(formatter.format(-1 * ONE_MINUTE, WorkDurationFormatter.Format.SHORT)).isEqualTo("-1min"); - } - -}