package com.xenoage.zong; import com.xenoage.utils.document.command.Command; import com.xenoage.utils.jse.io.JseFileUtils; import com.xenoage.utils.jse.lang.LangManager; import com.xenoage.utils.jse.lang.LanguageReader; import com.xenoage.utils.lang.Language; import com.xenoage.utils.lang.VocID; import com.xenoage.zong.desktop.utils.JseZongPlatformUtils; import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; import static com.xenoage.utils.collections.CollectionUtils.llist; import static com.xenoage.utils.io.FileFilters.javaFilter; import static com.xenoage.utils.jse.io.JseFileUtils.getFilter; import static com.xenoage.utils.jse.io.JseFileUtils.listFilesDeep; import static com.xenoage.utils.lang.VocByString.voc; /** * This class contains tests for the language packages. * * The English package ("en") is defined as the reference package, * which should be complete (this is also tested here). * * The tests checks * <ul> * <li>the usage of the defined vocabulary items in {@link Voc} in the program:</li> * <ul> * <li>each word in the {@link Voc} class must be referenced at least one time * by looking at all java files</li> * </ul> * <li>the reference package:</li> * <ul> * <li>the {@link Voc} words are implicitly complete, because they are given in the source code</li> * <li>for each {@link Command} there must be a name</li> * </ul> * <li>all translations:</li> * <ul> * <li>for each word from the reference package: is it defined in this package?</li> * <li>for each word from this package: is it defined in the reference package?</li> * </ul> * </ul> * * The result (including missing or unneeded words) is written to the * <code>{@value #logFileName}</code> file. * * @author Andreas Wenger */ public class VocabularyTry { private String referenceID = "en"; private String[] translationIDs = new String[] { "de" }; private Language referencePackage = null; private Language[] translationPackages = new Language[translationIDs.length]; private static final String logFileName = "VocabularyTryResult.txt"; private PrintStream logFile = null; public static void main(String... args) throws Exception { JseZongPlatformUtils.init(Zong.filename + "/" + VocabularyTry.class.getName()); VocabularyTry test = new VocabularyTry(); test.setUp(); test.testAllVocWordsUsed(); test.testReferenceCommandNames(); test.testTranslationCompleteness(); test.testTranslationMinimality(); test.close(); } public void setUp() throws IOException { //open file for logging logFile = new PrintStream(logFileName, "UTF-8"); //load reference package referencePackage = LanguageReader.read(LangManager.defaultLangPath, referenceID); for (VocID voc : Voc.values()) { if (referencePackage.getWithNull(voc) == null) referencePackage.add(voc.toString(), voc.getDefaultValue()); } //load translation packages for (int i = 0; i < translationPackages.length; i++) { translationPackages[i] = LanguageReader.read(LangManager.defaultLangPath, translationIDs[i]); } } /** * Tests, if all words of the given project are used (see class documentation). * No real Java parsing is done. Instead, just <code>"Voc."+id</code> is searched. */ public void testAllVocWordsUsed() { //collect all Voc values LinkedList<VocID> remaining = llist((VocID[]) Voc.values()); //search in all .java files in src folder Collection<File> files = listFilesDeep(new File(".."), getFilter(javaFilter)); for (File file : files) { String fileContent = JseFileUtils.readFile(file); remaining.removeIf(voc -> fileContent.contains("Voc." + voc.getID())); } //print all remaining elements if (remaining.size() > 0) { logFile.println("\nUnneeded Voc items:"); for (VocID voc : remaining) { logFile.println(voc); } } //assertEquals("There are unneeded Voc items", 0, remaining.size()); } /** * Tests, if each class extending the {@link Command} class, which is not * abstract, has a name in the reference language pack. */ public void testReferenceCommandNames() { String cmdPackage = "com.xenoage.zong.commands."; ArrayList<Class<?>> commands = SubclassCollector.getClassesImplementing(Command.class); //if there are less than 10 commands, something went wrong if (commands.size() < 10) logFile.println("Warning: Less then 10 commands - seems to be an error!"); //walk through all commands for (Class<?> cls : commands) { //test only commands in cmdPackage, ignore test commands in "test." package //and ignore abstract classes String clsName = cls.getName(); String packageName = clsName.substring(cmdPackage.length()); if (clsName.startsWith(cmdPackage) && !packageName.startsWith("test.") && !Modifier.isAbstract(cls.getModifiers())) { //look for name if (referencePackage.getWithNull(voc(clsName)) == null) { logFile.println("Vocabulary for Command \"" + clsName + "\" not found in language \"" + referenceID + "\""); } } } } /** * Tests, if each word from the reference package is defined in the other packages * of the given project (see class documentation). */ public void testTranslationCompleteness() throws Exception { for (Language pack : translationPackages) { if (pack.getID().equals(referencePackage.getID())) continue; //check other language LinkedList<String> unknown = new LinkedList<>(); for (String key : referencePackage.getAllKeys()) { if (pack.getWithNull(key) == null) unknown.add(key); } //print all unknown elements if (unknown.size() > 0) { logFile.println("\nMissing elements in language \"" + pack.getID() + "\":"); for (String voc : unknown) { logFile.println(voc); } } //assertEquals("The language \"" + pack.getID() + "\" is incomplete", 0, unknown.size()); } } /** * Tests, if each word of the other packages can also be found in the * reference package (see class documentation). */ public void testTranslationMinimality() throws Exception { for (Language pack : translationPackages) { if (pack.getID().equals(referencePackage.getID())) continue; //check other language LinkedList<String> unused = new LinkedList<>(); for (String key : pack.getAllKeys()) { //look for a reference language item with the same name if (!referencePackage.getAllKeys().contains(key)) { unused.add(key); } } //print all unused elements if (unused.size() > 0) { logFile.println("\nUnneeded elements in language \"" + pack.getID() + "\":"); for (String voc : unused) { logFile.println(voc); } } //assertEquals("The language \"" + pack.getID() + "\" is not minimal.", 0, unused.size()); } } public void close() { logFile.close(); } }