diff options
author | Julien Lancelot <julien.lancelot@sonarsource.com> | 2014-01-23 16:33:50 +0100 |
---|---|---|
committer | Julien Lancelot <julien.lancelot@sonarsource.com> | 2014-01-23 18:13:38 +0100 |
commit | 453366ae42491d3927249f44da40f6e947f30613 (patch) | |
tree | 3a1156f9fa97406209bf893ae6175262d4fd11a6 /sonar-core | |
parent | bd12c6abf52d4d1c1a3f1327eacca53e803dee23 (diff) | |
download | sonarqube-453366ae42491d3927249f44da40f6e947f30613.tar.gz sonarqube-453366ae42491d3927249f44da40f6e947f30613.zip |
Add a ago and instant method in i18n
Diffstat (limited to 'sonar-core')
5 files changed, 297 insertions, 7 deletions
diff --git a/sonar-core/src/main/java/org/sonar/core/i18n/DurationLabel.java b/sonar-core/src/main/java/org/sonar/core/i18n/DurationLabel.java new file mode 100644 index 00000000000..f560a26a54f --- /dev/null +++ b/sonar-core/src/main/java/org/sonar/core/i18n/DurationLabel.java @@ -0,0 +1,123 @@ +/* + * 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 com.google.common.annotations.VisibleForTesting; +import org.apache.commons.lang.StringUtils; + +import javax.annotation.CheckForNull; + +class DurationLabel { + + private static String durationPreffix = "duration."; + private static String suffixAgo = ".ago"; + private static String seconds = "seconds"; + private static String minute = "minute"; + private static String minutes = "minutes"; + private static String hour = "hour"; + private static String hours = "hours"; + private static String day = "day"; + private static String days = "days"; + private static String month = "month"; + private static String months = "months"; + private static String year = "year"; + private static String years = "years"; + + public static Result instant(long durationInMillis) { + return label(durationInMillis, false); + } + + public static Result ago(long durationInMillis) { + return label(durationInMillis, true); + } + + public static Result label(long durationInMillis, boolean addAgoSuffix) { + double nbSeconds = durationInMillis / 1000.0; + double nbMinutes = nbSeconds / 60; + double nbHours = nbMinutes / 60; + double nbDays = nbHours / 24; + double nbYears = nbDays / 365; + return getMessage(addAgoSuffix, nbSeconds, nbMinutes, nbHours, nbDays, nbYears); + } + + private static Result message(boolean addAgoSuffix, String key) { + return message(addAgoSuffix, key, null); + } + + private static Result message(boolean addAgoSuffix, String key, Long value) { + return new Result(join(durationPreffix, key, addAgoSuffix ? suffixAgo : null), value); + } + + private static Result getMessage(boolean addAgoSuffix, double nbSeconds, double nbMinutes, double nbHours, double nbDays, double nbYears) { + if (nbSeconds < 45) { + return message(addAgoSuffix, DurationLabel.seconds); + } else if (nbSeconds < 90) { + return message(addAgoSuffix, DurationLabel.minute); + } else if (nbMinutes < 45) { + return message(addAgoSuffix, DurationLabel.minutes, Math.round(nbMinutes)); + } else if (nbMinutes < 90) { + return message(addAgoSuffix, DurationLabel.hour); + } else if (nbHours < 24) { + return message(addAgoSuffix, DurationLabel.hours, Math.round(nbHours)); + } else if (nbHours < 48) { + return message(addAgoSuffix, DurationLabel.day); + } else if (nbDays < 30) { + return message(addAgoSuffix, DurationLabel.days, Double.valueOf(Math.floor(nbDays)).longValue()); + } else if (nbDays < 60) { + return message(addAgoSuffix, DurationLabel.month); + } else if (nbDays < 365) { + return message(addAgoSuffix, DurationLabel.months, Double.valueOf(Math.floor(nbDays / 30)).longValue()); + } else if (nbYears < 2) { + return message(addAgoSuffix, DurationLabel.year); + } + return message(addAgoSuffix, DurationLabel.years, Double.valueOf(Math.floor(nbYears)).longValue()); + } + + @VisibleForTesting + static String join(String first, String second, String last) { + StringBuilder joined = new StringBuilder(); + joined.append(first); + joined.append(second); + if (StringUtils.isNotBlank(last)) { + joined.append(last); + } + return joined.toString(); + } + + static class Result { + private String key; + private Long value; + + public Result(String key, Long value) { + this.key = key; + this.value = value; + } + + public String key() { + return key; + } + + @CheckForNull + public Long value() { + return value; + } + } + +} diff --git a/sonar-core/src/main/java/org/sonar/core/i18n/I18nManager.java b/sonar-core/src/main/java/org/sonar/core/i18n/I18nManager.java index 8ae6feeea41..720fbd40cc8 100644 --- a/sonar-core/src/main/java/org/sonar/core/i18n/I18nManager.java +++ b/sonar-core/src/main/java/org/sonar/core/i18n/I18nManager.java @@ -38,12 +38,7 @@ import javax.annotation.Nullable; import java.io.IOException; import java.io.InputStream; import java.text.MessageFormat; -import java.util.Enumeration; -import java.util.Locale; -import java.util.Map; -import java.util.MissingResourceException; -import java.util.ResourceBundle; -import java.util.Set; +import java.util.*; public class I18nManager implements I18n, ServerExtension, BatchExtension, Startable { private static final Logger LOG = LoggerFactory.getLogger(I18nManager.class); @@ -119,6 +114,16 @@ public class I18nManager implements I18n, ServerExtension, BatchExtension, Start return formatMessage(value, parameters); } + public String instant(Locale locale, long durationInMillis) { + DurationLabel.Result duration = DurationLabel.instant(durationInMillis); + return message(locale, duration.key(), null, duration.value()); + } + + public String ago(Locale locale, long durationInMillis) { + DurationLabel.Result duration = DurationLabel.ago(durationInMillis); + return message(locale, duration.key(), null, duration.value()); + } + /** * 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/test/java/org/sonar/core/i18n/DurationLabelTest.java b/sonar-core/src/test/java/org/sonar/core/i18n/DurationLabelTest.java new file mode 100644 index 00000000000..583fb7fb200 --- /dev/null +++ b/sonar-core/src/test/java/org/sonar/core/i18n/DurationLabelTest.java @@ -0,0 +1,150 @@ +/* + * 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.Test; +import org.junit.runner.RunWith; +import org.mockito.runners.MockitoJUnitRunner; + +import static org.fest.assertions.Assertions.assertThat; + +@RunWith(MockitoJUnitRunner.class) +public class DurationLabelTest { + + // One second in milliseconds + private static final long SECOND = 1000; + + // One minute in milliseconds + private static final long MINUTE = 60 * SECOND; + + // One hour in milliseconds + private static final long HOUR = 60 * MINUTE; + + // One day in milliseconds + private static final long DAY = 24 * HOUR; + + // 30 days in milliseconds + private static final long MONTH = 30 * DAY; + + // 365 days in milliseconds + private static final long YEAR = 365 * DAY; + + @Test + public void instant_seconds() { + long now = System.currentTimeMillis(); + DurationLabel.Result result = DurationLabel.instant(now - System.currentTimeMillis()); + assertThat(result.key()).isEqualTo("duration.seconds"); + assertThat(result.value()).isNull(); + } + + @Test + public void ago_seconds() { + long now = System.currentTimeMillis(); + DurationLabel.Result result = DurationLabel.ago(now - System.currentTimeMillis()); + assertThat(result.key()).isEqualTo("duration.seconds.ago"); + assertThat(result.value()).isNull(); + } + + @Test + public void ago_minute() { + DurationLabel.Result result = DurationLabel.label(now() - ago(MINUTE), true); + assertThat(result.key()).isEqualTo("duration.minute.ago"); + assertThat(result.value()).isNull(); + } + + @Test + public void ago_minutes() { + long minutes = 2; + DurationLabel.Result result = DurationLabel.label(now() - ago(minutes * MINUTE), true); + assertThat(result.key()).isEqualTo("duration.minutes.ago"); + assertThat(result.value()).isEqualTo(minutes); + + } + + @Test + public void ago_hour() { + DurationLabel.Result result = DurationLabel.label(now() - ago(HOUR), true); + assertThat(result.key()).isEqualTo("duration.hour.ago"); + assertThat(result.value()).isNull(); + } + + @Test + public void ago_hours() { + long hours = 3; + DurationLabel.Result result = DurationLabel.label(now() - ago(hours * HOUR), true); + assertThat(result.key()).isEqualTo("duration.hours.ago"); + assertThat(result.value()).isEqualTo(hours); + } + + @Test + public void ago_day() { + DurationLabel.Result result = DurationLabel.label(now() - ago(30 * HOUR), true); + assertThat(result.key()).isEqualTo("duration.day.ago"); + assertThat(result.value()).isNull(); + } + + @Test + public void ago_days() { + long days = 4; + DurationLabel.Result result = DurationLabel.label(now() - ago(days * DAY), true); + assertThat(result.key()).isEqualTo("duration.days.ago"); + assertThat(result.value()).isEqualTo(days); + } + + @Test + public void ago_month() { + DurationLabel.Result result = DurationLabel.label(now() - ago(35 * DAY), true); + assertThat(result.key()).isEqualTo("duration.month.ago"); + assertThat(result.value()).isNull(); + } + + @Test + public void ago_months() { + long months = 2; + DurationLabel.Result result = DurationLabel.label(now() - ago(months * MONTH), true); + assertThat(result.key()).isEqualTo("duration.months.ago"); + assertThat(result.value()).isEqualTo(months); + } + + @Test + public void year_ago() { + DurationLabel.Result result = DurationLabel.label(now() - ago(14 * MONTH), true); + assertThat(result.key()).isEqualTo("duration.year.ago"); + assertThat(result.value()).isNull(); + } + + @Test + public void years_ago() { + long years = 7; + DurationLabel.Result result = DurationLabel.label(now() - ago(years * YEAR), true); + assertThat(result.key()).isEqualTo("duration.years.ago"); + assertThat(result.value()).isEqualTo(years); + } + + private long ago(long offset) { + return System.currentTimeMillis() - offset; + } + + private long now() { + // Add 5 seconds in order to have zero false positive + return System.currentTimeMillis() + 5000; + } + +} diff --git a/sonar-core/src/test/java/org/sonar/core/i18n/I18nManagerTest.java b/sonar-core/src/test/java/org/sonar/core/i18n/I18nManagerTest.java index 49558738dff..6445fc256aa 100644 --- a/sonar-core/src/test/java/org/sonar/core/i18n/I18nManagerTest.java +++ b/sonar-core/src/test/java/org/sonar/core/i18n/I18nManagerTest.java @@ -159,6 +159,16 @@ public class I18nManagerTest { assertThat(html).isNull(); } + @Test + public void get_time_ago() { + assertThat(manager.ago(Locale.ENGLISH, 10)).isEqualTo("less than a minute ago"); + } + + @Test + public void get_time_instant() { + assertThat(manager.instant(Locale.ENGLISH, 10)).isEqualTo("less than a minute"); + } + static URLClassLoader newCoreClassloader() { return newClassLoader("/org/sonar/core/i18n/corePlugin/"); } 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 de205d651cb..f3e62c46cf7 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 @@ -1,4 +1,6 @@ by=By empty= with.parameters=First is {0} and second is {1} -only.in.english=Missing in French bundle
\ No newline at end of file +only.in.english=Missing in French bundle +duration.seconds=less than a minute +duration.seconds.ago=less than a minute ago |