/** * Copyright 2015 Santhosh Kumar Tekuri * * The JLibs authors license this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package jlibs.core.i18n; import jlibs.core.io.IOUtil; import jlibs.core.lang.ClassUtil; import jlibs.core.net.URLUtil; import jlibs.core.util.i18n.I18N; import org.testng.Assert; import org.testng.annotations.Test; import javax.tools.JavaCompiler; import javax.tools.ToolProvider; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import static jlibs.core.i18n.Bundle1.BUNDLE1; import static jlibs.core.i18n.Bundle2.BUNDLE2; /** * @author Santhosh Kumar T */ public class ResourceBundleTest{ private String compile(String... files){ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); ArrayList<String> args = new ArrayList<String>(); args.add("-d"); args.add(ClassUtil.getClassPath(getClass())); args.add("-s"); args.add(ClassUtil.getClassPath(getClass())); for(String file: files){ URL url = getClass().getResource(file); args.add(URLUtil.toSystemID(url)); } ByteArrayOutputStream err = new ByteArrayOutputStream(); if(compiler.run(null, null, err, args.toArray(new String[args.size()]))==0) return null; return err.toString(); } private void assertErrors(String errors, String... searchFor){ if(searchFor.length==0) Assert.assertNull(errors, "compilation failed with errors:\n"+errors); else{ errors = errors.replace('\\', '/'); errors = errors.replace("\r\n", "\n"); for(String error: searchFor){ if(errors.indexOf(error)==-1) Assert.fail("[Expected Error] "+error+"\n[Actual Error] "+errors); } } } @Test(description="@ResourceBundle can't be applied on class") public void classBundle(){ assertErrors(compile("/i18n/ClassBundle.java"), "i18n/ClassBundle.java:12: jlibs.core.util.i18n.ResourceBundle annotation can be applied only for interface\n" + "public abstract class ClassBundle{\n" + " ^" ); } @Test(description="methods in interface must have @Message") public void missingMessageAnnotation(){ assertErrors(compile("/i18n/MissingMessageAnnotationBundle.java"), "i18n/MissingMessageAnnotationBundle.java:", ": jlibs.core.util.i18n.Message annotation is missing on this method\n" + " public String lastSucussfullLogin(Date date);\n" + " ^" ); } @Test(description="method with @Message must return String") public void invalidMethodReturn(){ assertErrors(compile("/i18n/InvalidMethodReturnBundle.java"), "i18n/InvalidMethodReturnBundle.java:14: method annotated with jlibs.core.util.i18n.Message must return java.lang.String or a subclass of java.lang.Throwable\n" + " public Date lastSucussfullLogin(Date date);\n" + " ^" ); } @Test(description="invalid formats in message") public void invalidMessageFormat(){ assertErrors(compile("/i18n/InvalidMessageFormatBundle.java"), "Invalid Message Format: unknown format type at" ); } @Test(description="number of parameter in message and method should match") public void argumentCountMismatch(){ assertErrors(compile("/i18n/ArgumentCountMismatchBundle.java"), "no of args in message format doesn't match with the number of parameters this method accepts" ); } @Test(description="all method arguments must be used in message") public void missingArgument(){ assertErrors(compile("/i18n/MissingArgumentBundle.java"), "/i18n/MissingArgumentBundle.java:", ": {1} is missing in message\n" + " @Message(\"SQL Execution completed in {0} seconds with {2} errors and {2} warnings\")\n" + " ^" ); } @Test(description="two methods in a java file can't have same key") public void duplicateKeyInSameFile(){ assertErrors(compile("/i18n/DuplicateKeyBundle.java"), "key 'JLIBS015' is already used by \"public java.lang.String executionFinished(long, int, int)\" in i18n.DuplicateKeyBundle interface" ); } @Test(description="two methods in two interfaces can't have same key") public void duplicateKeyAcrossFiles(){ assertErrors(compile("/i18n/DuplicateKey1Bundle.java", "/i18n/DuplicateKey2Bundle.java"), "key 'JLIBS015' is already used by \"public java.lang.String executionFinished(long, int, int)\" in i18n.DuplicateKey1Bundle interface" ); } @Test(description="two methods in two interfaces can't have same signature") public void methodSignatureClash(){ assertErrors(compile("/i18n/MethodSignatureClash1Bundle.java", "/i18n/MethodSignatureClash2Bundle.java"), "i18n/MethodSignatureClash2Bundle.java:12: clashes with similar method in i18n.MethodSignatureClash1Bundle interface\n" + " public String executing(String query);" ); } @Test(description="test generated interface implementation methods") public void testImplementation(){ Assert.assertEquals(BUNDLE1.executing("myquery"), "executing myquery"); Assert.assertEquals(BUNDLE2.executed("myquery"), "executed myquery"); } @Test(description="test whether custom key is used") public void testCustomKey(){ Assert.assertEquals(BUNDLE1.executionTook(10), "execution took 10 seconds"); Assert.assertEquals(I18N.getValue(Bundle1.class, "timeTaken", 10), "execution took 10 seconds"); } @Test(description="test that documentation is generated in properties file") public void testDocumentation() throws IOException{ String props = IOUtil.pump(Bundle1.class.getResourceAsStream("Bundle.properties"), true).toString(); props = props.replace("\r\n", "\n"); if(props.indexOf("# {0} query\nexecuted=executed {0}")==-1) Assert.fail("documentation must be generated for method with no javadoc"); if(props.indexOf("# {0} time ==> time taken in seconds\ntimeTaken=execution took {0, number} seconds")==-1) Assert.fail("documentation must be generated for method with javadoc"); if(props.indexOf("# {0} query\nexecuting=executing {0}")==-1) Assert.fail("documentation must be generated for method with javadoc with no param description"); } }