001/* 002 * Sonar, open source software quality management tool. 003 * Copyright (C) 2008-2012 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * Sonar is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * Sonar is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License along with Sonar; if not, write to the Free Software 018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 019 */ 020package org.sonar.test.i18n; 021 022import com.google.common.collect.Maps; 023import org.apache.commons.io.FileUtils; 024import org.apache.commons.lang.StringUtils; 025import org.sonar.test.TestUtils; 026 027import java.io.File; 028import java.net.URI; 029import java.net.URISyntaxException; 030import java.util.Collection; 031import java.util.Map; 032 033import static org.junit.Assert.assertThat; 034import static org.junit.Assert.fail; 035 036public final class I18nMatchers { 037 038 private I18nMatchers() { 039 } 040 041 /** 042 * <p> 043 * <b>Used by language packs that translate Core bundles.</b> 044 * </p> 045 * Returns a matcher which checks that a translation bundle is up to date with the corresponding English Core bundle. 046 * <ul> 047 * <li>If a version of Sonar is specified, then the check is done against this version of the bundle found on Sonar Github repository.</li> 048 * <li>If sonarVersion is set to NULL, the check is done against the latest version of this bundle found on Github (master branch).</li> 049 * </ul> 050 * 051 * @param sonarVersion 052 * the version of the bundle to check against, or NULL to check against the latest source on GitHub 053 * @return the matcher 054 */ 055 public static BundleSynchronizedMatcher isBundleUpToDate(String sonarVersion) { 056 return new BundleSynchronizedMatcher(sonarVersion); 057 } 058 059 /** 060 * <p> 061 * <b>Used by language packs that translate third-party bundles.</b> 062 * </p> 063 * Returns a matcher which checks that a translation bundle is up to date with the given reference English bundle from a third-party plugin. 064 * 065 * @param referenceEnglishBundleURI 066 * the URI referencing the English bundle to check against 067 * @return the matcher 068 */ 069 public static BundleSynchronizedMatcher isBundleUpToDate(URI referenceEnglishBundleURI) { 070 return new BundleSynchronizedMatcher(referenceEnglishBundleURI); 071 } 072 073 /** 074 * <p> 075 * <b>Used only by independent plugins that embeds their own bundles for every language.</b> 076 * </p> 077 * Returns a matcher which checks that a translation bundle is up to date with the corresponding default one found in the same folder. 078 * 079 * @return the matcher 080 */ 081 public static BundleSynchronizedMatcher isBundleUpToDate() { 082 return new BundleSynchronizedMatcher(); 083 } 084 085 /** 086 * <p> 087 * <b>Must be used only by independent plugins that embeds their own bundles for every language.</b> 088 * </p> 089 * Checks that all the translation bundles found on the classpath are up to date with the corresponding default one found in the same 090 * folder. 091 */ 092 public static void assertAllBundlesUpToDate() { 093 try { 094 assertAllBundlesUpToDate(null, null); 095 } catch (URISyntaxException e) { 096 // Ignore, this can't happen here 097 } 098 } 099 100 /** 101 * <p> 102 * <b>Must be used only by language packs.</b> 103 * </p> 104 * <p> 105 * Depending on the parameters, this method does the following: 106 * <ul> 107 * <li><b>sonarVersion</b>: checks that all the Core translation bundles found on the classpath are up to date with the corresponding English ones found on Sonar 108 * GitHub repository for the given Sonar version. 109 * <ul><li><i>Note: if sonarVersion is set to NULL, the check is done against the latest version of this bundles found the master branch of the GitHub repository.</i></li></ul> 110 * </li> 111 * <li><b>pluginIdsToBundleUrlMap</b>: checks that other translation bundles found on the classpath are up to date with the reference English bundles of the corresponding 112 * plugins given by the "pluginIdsToBundleUrlMap" parameter. 113 * </li> 114 * </ul> 115 * </p> 116 * <p><br> 117 * The following example will check that the translation of the Core bundles are up to date with version 3.2 of Sonar English Language Pack, and it 118 * will also check that the translation of the bundle of the Web plugin is up to date with the reference English bundle of version 1.2 of the Web plugin: 119 * <pre> 120 * Map<String, String> pluginIdsToBundleUrlMap = Maps.newHashMap(); 121 * pluginIdsToBundleUrlMap.put("web", "http://svn.codehaus.org/sonar-plugins/tags/sonar-web-plugin-1.2/src/main/resources/org/sonar/l10n/web.properties"); 122 * assertAllBundlesUpToDate("3.2", pluginIdsToBundleUrlMap); 123 * </pre> 124 * </p> 125 * 126 * @param sonarVersion 127 * the version of the bundles to check against, or NULL to check against the latest source on GitHub 128 * @param pluginIdsToBundleUrlMap 129 * a map that gives, for a given plugin, the URL of the English bundle that must be used to check the translation. 130 * @throws URISyntaxException if the provided URLs in the "pluginIdsToBundleUrlMap" parameter are not correct 131 */ 132 public static void assertAllBundlesUpToDate(String sonarVersion, Map<String, String> pluginIdsToBundleUrlMap) throws URISyntaxException { 133 File bundleFolder = TestUtils.getResource(BundleSynchronizedMatcher.L10N_PATH); 134 if (bundleFolder == null || !bundleFolder.isDirectory()) { 135 fail("No bundle found in '" + BundleSynchronizedMatcher.L10N_PATH + "'"); 136 } 137 138 Collection<File> bundles = FileUtils.listFiles(bundleFolder, new String[] {"properties"}, false); 139 Map<String, String> failedAssertionMessages = Maps.newHashMap(); 140 for (File bundle : bundles) { 141 String bundleName = bundle.getName(); 142 if (bundleName.indexOf('_') > 0) { 143 try { 144 String baseBundleName = BundleSynchronizedMatcher.extractDefaultBundleName(bundleName); 145 String pluginId = StringUtils.substringBefore(baseBundleName, "."); 146 if (BundleSynchronizedMatcher.isCoreBundle(baseBundleName)) { 147 // this is a core bundle => must be checked againt the provided version of Sonar 148 assertThat(bundleName, isBundleUpToDate(sonarVersion)); 149 } else if (pluginIdsToBundleUrlMap != null && pluginIdsToBundleUrlMap.get(pluginId) != null) { 150 // this is a third-party plugin translated by a language pack => must be checked against the provided URL 151 assertThat(bundleName, isBundleUpToDate(new URI(pluginIdsToBundleUrlMap.get(pluginId)))); 152 } else { 153 // this is the case of a plugin that provides all the bundles for every language => check the bundles inside the plugin 154 assertThat(bundleName, isBundleUpToDate()); 155 } 156 } catch (AssertionError e) { 157 failedAssertionMessages.put(bundleName, e.getMessage()); 158 } 159 } 160 } 161 162 if (!failedAssertionMessages.isEmpty()) { 163 StringBuilder message = new StringBuilder(); 164 message.append(failedAssertionMessages.size()); 165 message.append(" bundles are not up-to-date: "); 166 message.append(StringUtils.join(failedAssertionMessages.keySet(), ", ")); 167 message.append("\n\n"); 168 message.append(StringUtils.join(failedAssertionMessages.values(), "\n\n")); 169 fail(message.toString()); 170 } 171 } 172}