Index: tmp/org.txm.core.tests/src/org/txm/core/tests/junit/PluginXMLIDs.java
===================================================================
--- tmp/org.txm.core.tests/src/org/txm/core/tests/junit/PluginXMLIDs.java	(revision 0)
+++ tmp/org.txm.core.tests/src/org/txm/core/tests/junit/PluginXMLIDs.java	(revision 357)
@@ -0,0 +1,74 @@
+package org.txm.core.tests.junit;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.LinkedHashSet;
+
+import org.txm.utils.io.IOUtils;
+
+public class PluginXMLIDs extends TXMPluginTest {
+
+	@Override
+	public void TBXPluginTest(File projectDirectory, String name, String packagePath) throws IOException {
+
+	}
+
+	@Override
+	public void RCPPluginTest(File projectDirectory, String name, String packagePath) throws IOException {
+		File pluginXML = new File(projectDirectory, "plugin.xml");
+		if (!pluginXML.exists()) {
+			error("missing file "+pluginXML);
+		}
+		File javaSrcDirectory = getJavaSrcDirectory(projectDirectory);
+
+		LinkedHashSet<String> ids = new LinkedHashSet<String>();
+		ids.addAll(IOUtils.findWithGroup(pluginXML, "id=\"([^\"]+)\""));
+		for (String id : ids) {
+			if (id.startsWith(name)) {
+				//System.out.println("id="+id);
+				String path = id.substring(0, id.lastIndexOf(".")).replace(".", "/");
+				String className = id.substring(id.lastIndexOf(".")+1);
+				if (className.matches("[A-Z].+")) {
+					File classFile = new File(javaSrcDirectory, path+"/"+className+".java");
+					if (!classFile.exists()) {
+						error("unbound id	"+id+"	"+classFile);
+					}
+				}
+			}
+		}
+
+		testClassExistance(pluginXML, javaSrcDirectory, name, "id=\"([^\"]+)\"", "id");
+		testClassExistance(pluginXML, javaSrcDirectory, name, "adaptableType=\"([^\"]+)\"", "adaptableType");
+		testClassExistance(pluginXML, javaSrcDirectory, name, "class=\"([^\"]+)\"", "class");
+		testClassExistance(pluginXML, javaSrcDirectory, name, "class=\"([^\"]+)\"", "commandId");
+		testClassExistance(pluginXML, javaSrcDirectory, name, "class=\"([^\"]+)\"", "defaultHandler");
+		testClassExistance(pluginXML, javaSrcDirectory, name, "instanceof value=\"([^\"]+)\"", "instanceof");
+	}
+
+	/**
+	 * 
+	 * @param pluginXML plugin.xml file
+	 * @param javaSrcDirectory the Java source directory (contains the class to find)
+	 * @param name the package to test
+	 * @param pattern the pattern to match. must contains ONE group
+	 * @param type the attribute to test
+	 * @throws IOException
+	 */
+	private void testClassExistance(File pluginXML, File javaSrcDirectory, String name, String pattern, String type) throws IOException {
+		LinkedHashSet<String> classes = new LinkedHashSet<String>();
+		classes.addAll(IOUtils.findWithGroup(pluginXML, pattern, true));
+		for (String id : classes) {
+			if (id.startsWith(name)) {
+				//System.out.println("id="+id);
+				String path = id.substring(0, id.lastIndexOf(".")).replace(".", "/");
+				String className = id.substring(id.lastIndexOf(".")+1);
+				if (className.matches("[A-Z].+")) {
+					File classFile = new File(javaSrcDirectory, path+"/"+className+".java");
+					if (!classFile.exists()) {
+						error("unbound "+type+"	"+id+"	"+classFile);
+					}
+				}
+			}
+		}
+	}
+}
\ No newline at end of file

Property changes on: tmp/org.txm.core.tests/src/org/txm/core/tests/junit/PluginXMLIDs.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: tmp/org.txm.core.tests/src/org/txm/core/tests/junit/PluginPreferences.java
===================================================================
--- tmp/org.txm.core.tests/src/org/txm/core/tests/junit/PluginPreferences.java	(revision 0)
+++ tmp/org.txm.core.tests/src/org/txm/core/tests/junit/PluginPreferences.java	(revision 357)
@@ -0,0 +1,34 @@
+package org.txm.core.tests.junit;
+
+import static org.junit.Assert.fail;
+
+import java.io.File;
+
+public class PluginPreferences extends TXMPluginTest {
+
+	public void RCPPluginTest(File projectDirectory, String name, String packagePath) {
+		
+	}
+	
+	@Override
+	public void TBXPluginTest(File projectDirectory, String name, String packagePath) {
+		File javaSrcDirectory = getJavaSrcDirectory(projectDirectory);
+		File preferencePackageDirectory = new File(javaSrcDirectory, packagePath+"/preferences");
+		if (!preferencePackageDirectory.exists()) {
+			error(preferencePackageDirectory.getAbsolutePath()+" is missing.");
+			return;
+		}
+		
+		// test content
+		File[] files = preferencePackageDirectory.listFiles();
+		if (files == null) {
+			error("No preference class file.");
+			return;
+		}
+		int c = 0;
+		for (File prefFile : files) {
+			if (prefFile.getName().endsWith("Preferences.java")) c++;
+		}
+		if (c == 0) error("No preference class file in "+preferencePackageDirectory);
+	}
+}

Property changes on: tmp/org.txm.core.tests/src/org/txm/core/tests/junit/PluginPreferences.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: tmp/org.txm.core.tests/src/org/txm/core/tests/junit/AllTXMPluginTests.java
===================================================================
--- tmp/org.txm.core.tests/src/org/txm/core/tests/junit/AllTXMPluginTests.java	(revision 0)
+++ tmp/org.txm.core.tests/src/org/txm/core/tests/junit/AllTXMPluginTests.java	(revision 357)
@@ -0,0 +1,11 @@
+package org.txm.core.tests.junit;
+
+import org.junit.runner.RunWith;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+@RunWith(Suite.class)
+@SuiteClasses({ PluginPreferences.class, PluginMessages.class, PluginXMLIDs.class })
+public class AllTXMPluginTests {
+
+}

Property changes on: tmp/org.txm.core.tests/src/org/txm/core/tests/junit/AllTXMPluginTests.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: tmp/org.txm.core.tests/src/org/txm/core/tests/junit/PluginMessages.java
===================================================================
--- tmp/org.txm.core.tests/src/org/txm/core/tests/junit/PluginMessages.java	(revision 0)
+++ tmp/org.txm.core.tests/src/org/txm/core/tests/junit/PluginMessages.java	(revision 357)
@@ -0,0 +1,118 @@
+package org.txm.core.tests.junit;
+
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.Properties;
+
+import org.txm.utils.io.IOUtils;
+
+public class PluginMessages extends TXMPluginTest {
+
+	String langs[] = {"", "_fr", "_ru"};
+
+	@Override
+	public void TBXPluginTest(File projectDirectory, String name, String packagePath) throws UnsupportedEncodingException, FileNotFoundException, IOException {
+		commonTest(projectDirectory, name, packagePath);
+	}
+
+	@Override
+	public void RCPPluginTest(File projectDirectory, String name, String packagePath) throws UnsupportedEncodingException, FileNotFoundException, IOException {
+		commonTest(projectDirectory, name, packagePath);
+
+		File pluginXML = new File(projectDirectory, "plugin.xml");
+		try {
+			// OSGI-INF test
+			File OSGI = new File(projectDirectory, "OSGI-INF/l10n");
+			for (String lang : langs) {
+				File propertiesFile = new File(OSGI, "bundle"+lang+".properties");
+				if (!propertiesFile.exists()) {
+					error("No "+propertiesFile.getAbsolutePath());
+					return;
+				} else {
+					testKeys(propertiesFile, pluginXML, "=\"%([^\"]+)\"");
+				}
+			}
+
+		} catch (IOException e) {
+			error(e.getLocalizedMessage());
+			e.printStackTrace();
+		}
+	}
+
+	public void commonTest(File projectDirectory, String name, String packagePath) throws UnsupportedEncodingException, FileNotFoundException, IOException {
+		File javaSrcDirectory = getJavaSrcDirectory(projectDirectory);
+
+		File messagesPackageDirectory = new File(javaSrcDirectory, packagePath+"/messages");
+		if (!messagesPackageDirectory.exists()) {
+			error("missing file "+messagesPackageDirectory.getAbsolutePath());
+			return;
+		}
+
+		// test content
+		File[] files = messagesPackageDirectory.listFiles();
+		if (files == null) {
+			error("No messages class file.");
+			return;
+		}
+		int c = 0;
+
+		File classFile = null;
+		for (File file : files) {
+			if (file.getName().endsWith("Messages.java")) classFile = file;
+		}
+
+		if (classFile == null) {
+			error("missing Java file "+messagesPackageDirectory);
+			return;
+		}
+
+		for (String lang : langs) {
+			
+			File propertiesFile = new File(messagesPackageDirectory, "messages"+lang+".properties");
+			if (!propertiesFile.exists()) {
+				error("missing properties	"+propertiesFile.getAbsolutePath());
+				return;
+			} else {
+				testKeys(propertiesFile, classFile, "public static String ([^;]+);");
+			}
+		}
+	}
+
+	/**
+	 * Compare keys of @param propertiesFile with keys found in @param classFile with @param pattern
+	 * @param propertiesFile
+	 * @param classFile
+	 * @param pattern
+	 * @throws UnsupportedEncodingException
+	 * @throws FileNotFoundException
+	 * @throws IOException
+	 */
+	protected void testKeys(File propertiesFile, File classFile, String pattern) throws UnsupportedEncodingException, FileNotFoundException, IOException {
+		Properties props = new Properties();
+		props.load(IOUtils.getReader(propertiesFile, "UTF-8"));
+		
+		LinkedHashSet<String> keys = new LinkedHashSet<String>();
+		keys.addAll(IOUtils.findWithGroup(classFile, pattern));
+		
+		// find missing keys in prop file
+		for (String key : keys) {
+			if (props.getProperty(key) == null) {
+				error("missing key	'"+key+"'	"+propertiesFile.getName());
+			}
+		}
+		
+		// find unused keys
+		for (Object key : props.keySet()) {
+			String s = key.toString();
+			if (!keys.contains(s)) {
+				error("unused key	'"+key+"'	"+propertiesFile.getName());
+			}
+		}
+	}
+}

Property changes on: tmp/org.txm.core.tests/src/org/txm/core/tests/junit/PluginMessages.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: tmp/org.txm.core.tests/src/org/txm/core/tests/junit/TXMPluginTest.java
===================================================================
--- tmp/org.txm.core.tests/src/org/txm/core/tests/junit/TXMPluginTest.java	(revision 0)
+++ tmp/org.txm.core.tests/src/org/txm/core/tests/junit/TXMPluginTest.java	(revision 357)
@@ -0,0 +1,117 @@
+package org.txm.core.tests.junit;
+
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import org.junit.Test;
+
+public abstract class TXMPluginTest {
+	public static int LEVEL = 1; // 1 errors, 2 warnings, 3 infos messages
+	int error = 0;
+	
+	protected ArrayList<File> projects;
+	protected ArrayList<String> messages = new ArrayList<String>();
+	
+	
+	public static File workspace = new File(System.getProperty("user.home"), "workspace079");
+
+	protected static ArrayList<File> getProjects() {
+		ArrayList<File> ret = new ArrayList<File>();
+		if (!workspace.exists()) {
+			System.out.println("ERROR: "+workspace+" does not exists. Set it in TXMPluginTest.java.");
+			return ret;
+		} 
+
+		ret.addAll(Arrays.asList(workspace.listFiles(new FileFilter() {
+			@Override
+			public boolean accept(File pathname) {
+				return pathname.isDirectory() && (pathname.getName().endsWith(".rcp") || pathname.getName().endsWith(".core"));
+			}
+		})));
+
+		return ret;
+	}
+	
+
+	protected void error(String string) {
+		if (LEVEL >= 1) messages.add("	ERROR	"+string);
+		error++;
+	}
+
+	protected void warning(String string) {
+		if (LEVEL >= 2) messages.add("	WARNING	"+string);
+	}
+
+	protected void info(String string) {
+		if (LEVEL >= 3) messages.add("	INFO	"+string);
+	}
+	
+	/**
+	 * All Test must starts with "super.test();"
+	 */
+	@Test
+	public void test() {
+		
+		System.out.print("Testing "+this.getClass().getSimpleName()+"...");
+		try {
+		projects = getProjects();
+		
+		if (projects.size() == 0) fail("No project found in "+workspace);
+		
+		int nProjectMessage = 0;
+		for (File projectDirectory : projects) {
+			messages.clear();
+			String plugin_name = projectDirectory.getName();
+			String plugin_package = plugin_name.replace(".", "/");
+			
+			if (projectDirectory.getName().endsWith(".core")) {
+				//plugin_package = plugin_package.substring(0, plugin_package.length()-5);
+				TBXPluginTest(projectDirectory, plugin_name, plugin_package);
+			} else if (projectDirectory.getName().endsWith(".rcp")) {
+				//plugin_package = plugin_package.substring(0, plugin_package.length()-4);
+				RCPPluginTest(projectDirectory, plugin_name, plugin_package);
+			} else {
+				// ignore project
+			}
+			
+			if (messages.size() > 0) {
+				if (nProjectMessage == 0) {
+					System.out.println();
+					nProjectMessage++;
+				}
+				System.out.println(" P "+projectDirectory.getName());
+				for (String s : messages) System.out.println(s);
+			}
+			
+		}
+		} catch(Exception e) {
+			e.printStackTrace();
+			fail("Internal test error: "+e.getLocalizedMessage());
+		}
+		if (error > 0) {
+			fail("Errors during test "+this.getClass().getName());
+		} else System.out.println("OK!");
+	}
+	
+/**
+ * 
+ * @param projectDirectory
+ * @return the Java src directory src/main or src
+ */
+	protected static File getJavaSrcDirectory(File projectDirectory) {
+		File javaSrcDirectory = new File(projectDirectory, "src/main/java/");
+		if (!javaSrcDirectory.exists()) javaSrcDirectory = new File(projectDirectory, "src/java");
+		if (!javaSrcDirectory.exists()) javaSrcDirectory = new File(projectDirectory, "src/");
+		return javaSrcDirectory;
+	}
+	
+	public abstract void TBXPluginTest(File projectDirectory, String name, String packagePath) throws Exception;
+	public abstract void RCPPluginTest(File projectDirectory, String name, String packagePath) throws Exception;
+}

Property changes on: tmp/org.txm.core.tests/src/org/txm/core/tests/junit/TXMPluginTest.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: tmp/org.txm.core.tests/META-INF/MANIFEST.MF
===================================================================
--- tmp/org.txm.core.tests/META-INF/MANIFEST.MF	(revision 356)
+++ tmp/org.txm.core.tests/META-INF/MANIFEST.MF	(revision 357)
@@ -4,7 +4,8 @@
 Bundle-SymbolicName: org.txm.core.tests;singleton:=true
 Bundle-Version: 1.0.0.qualifier
 Bundle-RequiredExecutionEnvironment: JavaSE-1.6
-Require-Bundle: org.txm.lexicon.core,
+Require-Bundle: org.txm.utils,
+ org.txm.lexicon.core,
  org.eclipse.core.runtime;bundle-version="3.10.0",
  org.txm.core;bundle-version="0.7.0",
  org.txm.statsengine.r.core,
