rename bundles, projects and adopt the poms
Signed-off-by: Florian Thienel <florian@thienel.org>
diff --git a/org.eclipse.vex.ui.tests/.classpath b/org.eclipse.vex.ui.tests/.classpath
new file mode 100644
index 0000000..64c5e31
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.vex.ui.tests/.gitignore b/org.eclipse.vex.ui.tests/.gitignore
new file mode 100644
index 0000000..fe07c27
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/.gitignore
@@ -0,0 +1,2 @@
+bin

+/target
diff --git a/org.eclipse.vex.ui.tests/.project b/org.eclipse.vex.ui.tests/.project
new file mode 100644
index 0000000..9c235fb
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/.project
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<projectDescription>

+	<name>org.eclipse.vex.ui.tests</name>

+	<comment></comment>

+	<projects>

+	</projects>

+	<buildSpec>

+		<buildCommand>

+			<name>org.eclipse.jdt.core.javabuilder</name>

+			<arguments>

+			</arguments>

+		</buildCommand>

+		<buildCommand>

+			<name>org.eclipse.pde.ManifestBuilder</name>

+			<arguments>

+			</arguments>

+		</buildCommand>

+		<buildCommand>

+			<name>org.eclipse.pde.SchemaBuilder</name>

+			<arguments>

+			</arguments>

+		</buildCommand>

+		<buildCommand>

+			<name>org.eclipse.pde.api.tools.apiAnalysisBuilder</name>

+			<arguments>

+			</arguments>

+		</buildCommand>

+	</buildSpec>

+	<natures>

+		<nature>org.eclipse.pde.PluginNature</nature>

+		<nature>org.eclipse.jdt.core.javanature</nature>

+		<nature>org.eclipse.pde.api.tools.apiAnalysisNature</nature>

+	</natures>

+</projectDescription>

diff --git a/org.eclipse.vex.ui.tests/.settings/org.eclipse.core.resources.prefs b/org.eclipse.vex.ui.tests/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..9241652
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,3 @@
+#Sun Nov 01 00:52:51 GMT 2009
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/org.eclipse.vex.ui.tests/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.vex.ui.tests/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..9640e53
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,7 @@
+#Wed Oct 01 02:46:26 GMT 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/org.eclipse.vex.ui.tests/.settings/org.eclipse.pde.prefs b/org.eclipse.vex.ui.tests/.settings/org.eclipse.pde.prefs
new file mode 100644
index 0000000..a7deae5
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/.settings/org.eclipse.pde.prefs
@@ -0,0 +1,33 @@
+#Thu Dec 02 21:33:29 CET 2010

+compilers.f.unresolved-features=1

+compilers.f.unresolved-plugins=1

+compilers.incompatible-environment=1

+compilers.p.build=0

+compilers.p.build.bin.includes=1

+compilers.p.build.encodings=2

+compilers.p.build.java.compiler=2

+compilers.p.build.java.compliance=1

+compilers.p.build.missing.output=2

+compilers.p.build.output.library=1

+compilers.p.build.source.library=1

+compilers.p.build.src.includes=1

+compilers.p.deprecated=1

+compilers.p.discouraged-class=1

+compilers.p.internal=1

+compilers.p.missing-packages=1

+compilers.p.missing-version-export-package=2

+compilers.p.missing-version-import-package=2

+compilers.p.missing-version-require-bundle=2

+compilers.p.no-required-att=0

+compilers.p.not-externalized-att=1

+compilers.p.unknown-attribute=0

+compilers.p.unknown-class=1

+compilers.p.unknown-element=1

+compilers.p.unknown-identifier=1

+compilers.p.unknown-resource=0

+compilers.p.unresolved-ex-points=0

+compilers.p.unresolved-import=0

+compilers.s.create-docs=false

+compilers.s.doc-folder=doc

+compilers.s.open-tags=1

+eclipse.preferences.version=1

diff --git a/org.eclipse.vex.ui.tests/META-INF/MANIFEST.MF b/org.eclipse.vex.ui.tests/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..548f66a
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/META-INF/MANIFEST.MF
@@ -0,0 +1,19 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: org.eclipse.vex.ui.tests;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Vendor: %providerName
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.core.resources,
+ org.eclipse.vex.ui;bundle-version="0.5.0",
+ org.junit;bundle-version="3.8.1",
+ org.eclipse.jface.text;bundle-version="3.0.0"
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Export-Package: org.eclipse.wst.xml.vex.ui.internal.config.tests;x-internal:=true,
+ org.eclipse.wst.xml.vex.ui.internal.editor.tests;x-internal:=true,
+ org.eclipse.wst.xml.vex.ui.internal.tests;x-internal:=true,
+ org.eclipse.wst.xml.vex.ui.tests
+Bundle-Localization: plugin
+Bundle-ClassPath: .
diff --git a/org.eclipse.vex.ui.tests/build.properties b/org.eclipse.vex.ui.tests/build.properties
new file mode 100644
index 0000000..8cc14a1
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/build.properties
@@ -0,0 +1,7 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+               .,\
+               plugin.properties,\
+               plugin.xml,\
+               testdata/
diff --git a/org.eclipse.vex.ui.tests/plugin.properties b/org.eclipse.vex.ui.tests/plugin.properties
new file mode 100644
index 0000000..3d85c6a
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/plugin.properties
@@ -0,0 +1,13 @@
+###############################################################################
+# Copyright (c) 2009 David Carver and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+#     David Carver - initial API and implementation
+###############################################################################
+pluginName= Vex UI Tests
+providerName= Eclipse.org
+contentType.name=Vex Test XML Document Type

diff --git a/org.eclipse.vex.ui.tests/plugin.xml b/org.eclipse.vex.ui.tests/plugin.xml
new file mode 100644
index 0000000..3e3f131
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/plugin.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<?eclipse version="3.4"?>

+<plugin>

+	<extension point="org.eclipse.core.contenttype.contentTypes">

+		<content-type id="org.eclipse.wst.xml.vex.ui.tests" name="%contentType.name"

+			base-type="org.eclipse.wst.xml.vex.ui.XmlDocument" file-extensions="xml">

+		</content-type>

+	</extension>

+ <extension

+       point="org.eclipse.wst.xml.core.catalogContributions">

+    <catalogContribution

+          id="default">

+       <public

+             publicId="-//Vex//DTD Test//EN"

+             uri="testdata/test.dtd">

+       </public>

+    </catalogContribution>

+ </extension>

+   <extension

+         id="test-doctype"

+         name="test doctype"

+         point="org.eclipse.vex.ui.doctypes">

+      <doctype

+            systemId="test.dtd"

+            publicId="-//Vex//DTD Test//EN">

+      </doctype>

+   </extension>

+   <extension

+         id="test-style"

+         name="test style"

+         point="org.eclipse.vex.ui.styles">

+      <style

+            css="testdata/test.css">

+         <doctypeRef

+               publicId="-//Vex//DTD Test//EN">

+         </doctypeRef>

+      </style>

+   </extension>

+

+</plugin>

diff --git a/org.eclipse.vex.ui.tests/pom.xml b/org.eclipse.vex.ui.tests/pom.xml
new file mode 100644
index 0000000..234cafc
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/pom.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<artifactId>org.eclipse.vex.ui.tests</artifactId>
+	<packaging>eclipse-test-plugin</packaging>
+	<version>1.0.0-SNAPSHOT</version>
+	<name>Vex UI Tests</name>
+
+	<parent>
+		<artifactId>org.eclipse.vex-releng</artifactId>
+		<groupId>org.eclipse.vex</groupId>
+		<version>1.0.0-SNAPSHOT</version>
+		<relativePath>../org.eclipse.vex.releng/pom.xml</relativePath>
+	</parent>
+	
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.sonatype.tycho</groupId>
+				<artifactId>maven-osgi-test-plugin</artifactId>
+				<version>${tycho-version}</version>
+				<configuration>
+					<useUIHarness>true</useUIHarness>
+					<testSuite>org.eclipse.vex.ui.tests</testSuite>
+					<testClass>org.eclipse.wst.xml.vex.ui.tests.VexUiTestSuite</testClass>
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>	
+
+</project>
diff --git a/org.eclipse.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/internal/config/tests/ConfigLoaderJobTest.java b/org.eclipse.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/internal/config/tests/ConfigLoaderJobTest.java
new file mode 100644
index 0000000..847eb0a
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/internal/config/tests/ConfigLoaderJobTest.java
@@ -0,0 +1,114 @@
+/*******************************************************************************

+ * Copyright (c) 2010 Florian Thienel and others.

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * which accompanies this distribution, and is available at

+ * http://www.eclipse.org/legal/epl-v10.html

+ * 

+ * Contributors:

+ * 		Florian Thienel - initial API and implementation

+ *******************************************************************************/

+package org.eclipse.wst.xml.vex.ui.internal.config.tests;

+

+import static org.junit.Assert.assertFalse;

+import static org.junit.Assert.assertNotNull;

+import static org.junit.Assert.assertTrue;

+import static org.junit.Assert.fail;

+

+import java.util.HashSet;

+import java.util.List;

+

+import org.eclipse.core.resources.IProject;

+import org.eclipse.core.resources.IResource;

+import org.eclipse.wst.xml.vex.ui.internal.config.ConfigLoaderJob;

+import org.eclipse.wst.xml.vex.ui.internal.config.ConfigSource;

+import org.junit.Rule;

+import org.junit.Test;

+import org.junit.rules.TestName;

+

+/**

+ * @author Florian Thienel

+ */

+@SuppressWarnings("restriction")

+public class ConfigLoaderJobTest {

+

+	@Rule

+	public TestName name = new TestName();

+

+	@Test

+	public void loadUiTestsPluginConfiguration() throws Exception {

+		final ConfigLoaderJob job = new ConfigLoaderJob();

+		job.schedule();

+		job.join();

+		final List<ConfigSource> allConfigSources = job.getLoadedConfigSources();

+		assertContainsConfiguration(allConfigSources, "org.eclipse.wst.xml.vex.ui.tests", "test-doctype", "test-style");

+		assertContainsEachPluginOnlyOnce(allConfigSources);

+	}

+

+	@Test

+	public void loadWorkspacePluginConfiguration() throws Exception {

+		IProject pluginProject = PluginProjectTest.createVexPluginProject(name.getMethodName());

+		final ConfigLoaderJob job = new ConfigLoaderJob();

+		job.schedule();

+		job.join();

+		final List<ConfigSource> allConfigSources = job.getLoadedConfigSources();

+		assertContainsConfiguration(allConfigSources, name.getMethodName(), pluginProject.getFile("plugintest.dtd"), pluginProject.getFile("plugintest.css"));

+		assertContainsEachPluginOnlyOnce(allConfigSources);

+	}

+	

+	@Test

+	public void runRunnableWhenDone() throws Exception {

+		final boolean[] runnableRun = new boolean[2];

+		runnableRun[0] = false;

+		runnableRun[1] = false;

+		final ConfigLoaderJob job = new ConfigLoaderJob();

+		job.load(new Runnable() {

+			public void run() {

+				runnableRun[0] = true;

+			}

+		});

+		job.join();

+		assertTrue(runnableRun[0]);

+		assertFalse(runnableRun[1]);

+		

+		runnableRun[0] = false;

+		runnableRun[1] = false;

+		job.load(new Runnable() {

+			public void run() {

+				runnableRun[1] = true;

+			}

+		});

+		job.join();

+		assertFalse(runnableRun[0]);

+		assertTrue(runnableRun[1]);

+	}

+

+	private static void assertContainsConfiguration(final List<ConfigSource> configSources, final String uniqueIdentifier, final String... simpleIds) {

+		for (final ConfigSource configSource : configSources) {

+			if (uniqueIdentifier.equals(configSource.getUniqueIdentifer())) {

+				for (final String simpleId : simpleIds)

+					assertNotNull(simpleId + " is not configured", configSource.getItem(simpleId));

+				return;

+			}

+		}

+		fail("Cannot find configuration " + uniqueIdentifier);

+	}

+	

+	private static void assertContainsConfiguration(final List<ConfigSource> configSources, final String uniqueIdentifier, final IResource... configuredResources) {

+		for (final ConfigSource configSource : configSources) {

+			if (uniqueIdentifier.equals(configSource.getUniqueIdentifer())) {

+				for (final IResource configuredResource : configuredResources)

+					assertNotNull(configuredResource + " is not configured", configSource.getItemForResource(configuredResource));

+				return;

+			}

+		}

+		fail("Cannot find configuration " + uniqueIdentifier);

+	}

+

+	private static void assertContainsEachPluginOnlyOnce(final List<ConfigSource> configSources) {

+		final HashSet<String> configSourceIds = new HashSet<String>();

+		for (final ConfigSource configSource : configSources)

+			assertTrue("ConfigRegistry contains " + configSource.getUniqueIdentifer() + " twice.", configSourceIds.add(configSource.getUniqueIdentifer()));

+	}

+

+}

diff --git a/org.eclipse.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/internal/config/tests/ConfigurationRegistryTest.java b/org.eclipse.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/internal/config/tests/ConfigurationRegistryTest.java
new file mode 100644
index 0000000..1f4a3c7
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/internal/config/tests/ConfigurationRegistryTest.java
@@ -0,0 +1,162 @@
+/*******************************************************************************

+ * Copyright (c) 2010 Florian Thienel and others.

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * which accompanies this distribution, and is available at

+ * http://www.eclipse.org/legal/epl-v10.html

+ * 

+ * Contributors:

+ * 		Florian Thienel - initial API and implementation

+ *******************************************************************************/

+package org.eclipse.wst.xml.vex.ui.internal.config.tests;

+

+import static org.junit.Assert.assertFalse;

+import static org.junit.Assert.assertNotNull;

+import static org.junit.Assert.assertTrue;

+

+import java.io.ByteArrayInputStream;

+import java.util.Collections;

+import java.util.List;

+

+import org.eclipse.core.resources.IProject;

+import org.eclipse.wst.xml.vex.ui.internal.config.ConfigEvent;

+import org.eclipse.wst.xml.vex.ui.internal.config.ConfigSource;

+import org.eclipse.wst.xml.vex.ui.internal.config.ConfigurationLoader;

+import org.eclipse.wst.xml.vex.ui.internal.config.ConfigurationRegistry;

+import org.eclipse.wst.xml.vex.ui.internal.config.ConfigurationRegistryImpl;

+import org.eclipse.wst.xml.vex.ui.internal.config.IConfigListener;

+import org.eclipse.wst.xml.vex.ui.internal.config.PluginProject;

+import org.junit.After;

+import org.junit.Rule;

+import org.junit.Test;

+import org.junit.rules.TestName;

+

+/**

+ * @author Florian Thienel

+ */

+@SuppressWarnings("restriction")

+public class ConfigurationRegistryTest {

+

+	private ConfigurationRegistry registry;

+

+	@Rule

+	public TestName name = new TestName();

+

+	@After

+	public void disposeRegistry() {

+		if (registry != null)

+			registry.dispose();

+		registry = null;

+	}

+

+	@Test

+	public void notAutomaticallyLoaded() throws Exception {

+		registry = new ConfigurationRegistryImpl(new MockConfigurationLoader());

+		assertFalse(registry.isLoaded());

+	}

+

+	@Test

+	public void fireLoadedEventOnLoad() throws Exception {

+		registry = new ConfigurationRegistryImpl(new MockConfigurationLoader());

+		final MockConfigListener configListener = new MockConfigListener();

+		registry.addConfigListener(configListener);

+		registry.loadConfigurations();

+		assertTrue(registry.isLoaded());

+		assertTrue(configListener.loaded);

+		assertFalse(configListener.changed);

+	}

+

+	@Test

+	public void loadNewPluginProjectAndFireChangedEvent() throws Exception {

+		registry = new ConfigurationRegistryImpl(new MockConfigurationLoader());

+		final MockConfigListener configListener = new MockConfigListener();

+		registry.addConfigListener(configListener);

+		registry.loadConfigurations();

+		configListener.reset();

+		IProject project = PluginProjectTest.createVexPluginProject(name.getMethodName());

+		assertFalse(configListener.loaded);

+		assertTrue(configListener.changed);

+		assertNotNull(registry.getPluginProject(project));

+	}

+

+	@Test

+	public void reloadModifiedPluginProjectAndFireConfigChangedEvent() throws Exception {

+		registry = new ConfigurationRegistryImpl(new MockConfigurationLoader());

+		registry.loadConfigurations();

+		final IProject project = PluginProjectTest.createVexPluginProject(name.getMethodName());

+		final MockConfigListener configListener = new MockConfigListener();

+		project.getFile("plugintest2.css").create(new ByteArrayInputStream(new byte[0]), true, null);

+		final String fileContent = PluginProjectTest.createVexPluginFileContent(project, "plugintest.dtd", "plugintest.css", "plugintest2.css");

+		registry.addConfigListener(configListener);

+		project.getFile(PluginProject.PLUGIN_XML).setContents(new ByteArrayInputStream(fileContent.getBytes()), true, true, null);

+		assertFalse(configListener.loaded);

+		assertTrue(configListener.changed);

+		assertNotNull(registry.getPluginProject(project).getItemForResource(project.getFile("plugintest2.css")));

+	}

+

+	@Test

+	public void removeDeletedPluginProjectAndFireConfigChangedEvent() throws Exception {

+		registry = new ConfigurationRegistryImpl(new MockConfigurationLoader());

+		registry.loadConfigurations();

+		final IProject project = PluginProjectTest.createVexPluginProject(name.getMethodName());

+		final MockConfigListener configListener = new MockConfigListener();

+		registry.addConfigListener(configListener);

+		project.getFile("plugintest.css").delete(true, null);

+		assertTrue(configListener.changed);

+		assertNotNull(registry.getPluginProject(project));

+		configListener.reset();

+		project.getFile("plugintest.dtd").delete(true, null);

+		assertTrue(configListener.changed);

+		assertNotNull(registry.getPluginProject(project));

+		configListener.reset();

+		project.getFile(PluginProject.PLUGIN_XML).delete(true, null);

+		assertTrue(configListener.changed);

+		assertNotNull(registry.getPluginProject(project));

+	}

+	

+	private static class MockConfigurationLoader implements ConfigurationLoader {

+		private final List<ConfigSource> loadedConfigSources;

+

+		public MockConfigurationLoader() {

+			this(Collections.<ConfigSource> emptyList());

+		}

+

+		public MockConfigurationLoader(final List<ConfigSource> loadedConfigSources) {

+			this.loadedConfigSources = loadedConfigSources;

+		}

+

+		public void load(final Runnable whenDone) {

+			whenDone.run();

+		}

+

+		public boolean isLoading() {

+			return false;

+		}

+

+		public List<ConfigSource> getLoadedConfigSources() {

+			return loadedConfigSources;

+		}

+

+		public void join() throws InterruptedException {

+			return;

+		}

+	}

+

+	private static class MockConfigListener implements IConfigListener {

+		public boolean changed = false;

+		public boolean loaded = false;

+

+		public void configChanged(final ConfigEvent e) {

+			changed = true;

+		}

+

+		public void configLoaded(final ConfigEvent e) {

+			loaded = true;

+		}

+

+		public void reset() {

+			changed = false;

+			loaded = false;

+		}

+	}

+}

diff --git a/org.eclipse.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/internal/config/tests/PluginProjectTest.java b/org.eclipse.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/internal/config/tests/PluginProjectTest.java
new file mode 100644
index 0000000..82a5d12
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/internal/config/tests/PluginProjectTest.java
@@ -0,0 +1,81 @@
+/*******************************************************************************

+ * Copyright (c) 2010 Florian Thienel and others.

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * which accompanies this distribution, and is available at

+ * http://www.eclipse.org/legal/epl-v10.html

+ * 

+ * Contributors:

+ * 		Florian Thienel - initial API and implementation

+ *******************************************************************************/

+package org.eclipse.wst.xml.vex.ui.internal.config.tests;

+

+import java.io.ByteArrayInputStream;

+import java.io.PrintWriter;

+import java.io.StringWriter;

+

+import org.eclipse.core.resources.IProject;

+import org.eclipse.core.resources.IProjectDescription;

+import org.eclipse.core.resources.ResourcesPlugin;

+import org.eclipse.core.runtime.CoreException;

+import org.eclipse.wst.xml.vex.ui.internal.config.PluginProject;

+import org.eclipse.wst.xml.vex.ui.internal.config.PluginProjectNature;

+

+/**

+ * @author Florian Thienel

+ */

+@SuppressWarnings("restriction")

+public class PluginProjectTest {

+

+	public static IProject createVexPluginProject(final String name) throws CoreException {

+		final IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(name);

+		if (project.exists())

+			project.delete(true, true, null);

+		project.create(null);

+		project.open(null);

+		project.getFile("plugintest.dtd").create(new ByteArrayInputStream(new byte[0]), true, null);

+		project.getFile("plugintest.css").create(new ByteArrayInputStream(new byte[0]), true, null);

+		createVexPluginFile(project);

+		addVexProjectNature(project);

+		return project;

+	}

+

+	public static void createVexPluginFile(final IProject project) throws CoreException {

+		final String fileContent = createVexPluginFileContent(project);

+		project.getFile(PluginProject.PLUGIN_XML).create(new ByteArrayInputStream(fileContent.getBytes()), true, null);

+	}

+

+	public static String createVexPluginFileContent(final IProject project) {

+		return createVexPluginFileContent(project, "plugintest.dtd", "plugintest.css");

+	}

+

+	public static String createVexPluginFileContent(final IProject project, final String dtdFilename, final String... styleFilenames) {

+		final StringWriter result = new StringWriter();

+		final PrintWriter out = new PrintWriter(result);

+		out.println("<?xml version='1.0'?>"); //$NON-NLS-1$

+		// HINT: It is important to set the id attribute, because this is used as the unique identifier for the configuration. 

+		out.println("<plugin id=\"" + project.getName() + "\">"); //$NON-NLS-1$ //$NON-NLS-2$

+		out.println("<extension id=\"plugintest\" name=\"plugin test doctype\" point=\"org.eclipse.wst.xml.vex.ui.doctypes\">"); //$NON-NLS-1$

+		out.println("<doctype systemId=\"" + dtdFilename + "\" dtd=\"" + dtdFilename + "\" publicId=\"-//Vex//Plugin Test//EN\" />"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

+		out.println("</extension>"); //$NON-NLS-1$

+		for (final String styleFilename : styleFilenames) {

+			out.println("<extension id=\"plugintest\" name=\"plugin test style\" point=\"org.eclipse.wst.xml.vex.ui.styles\">"); //$NON-NLS-1$

+			out.println("<style css=\"" + styleFilename + "\"><doctypeRef publicId=\"-//Vex//Plugin Test//EN\" /></style>"); //$NON-NLS-1$ //$NON-NLS-2$

+			out.println("</extension>"); //$NON-NLS-1$

+		}

+		out.println("</plugin>"); //$NON-NLS-1$

+		out.close();

+		return result.toString();

+	}

+

+	public static void addVexProjectNature(final IProject project) throws CoreException {

+		final IProjectDescription description = project.getDescription();

+		final String[] natures = description.getNatureIds();

+		final String[] newNatures = new String[natures.length + 1];

+		System.arraycopy(natures, 0, newNatures, 0, natures.length);

+		newNatures[natures.length] = PluginProjectNature.ID;

+		description.setNatureIds(newNatures);

+		project.setDescription(description, null);

+	}

+

+}

diff --git a/org.eclipse.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/internal/editor/tests/FindReplaceTargetTest.java b/org.eclipse.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/internal/editor/tests/FindReplaceTargetTest.java
new file mode 100644
index 0000000..f2815e4
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/internal/editor/tests/FindReplaceTargetTest.java
@@ -0,0 +1,365 @@
+/*******************************************************************************

+ * Copyright (c) 2009 Holger Voormann and others.

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * which accompanies this distribution, and is available at

+ * http://www.eclipse.org/legal/epl-v10.html

+ *

+ * Contributors:

+ *     Holger Voormann - initial API and implementation

+ *******************************************************************************/

+package org.eclipse.wst.xml.vex.ui.internal.editor.tests;

+

+import java.util.regex.PatternSyntaxException;

+

+import junit.framework.TestCase;

+

+import org.eclipse.swt.graphics.Point;

+import org.eclipse.wst.xml.vex.ui.internal.editor.AbstractRegExFindReplaceTarget;

+

+@SuppressWarnings("restriction")

+public class FindReplaceTargetTest extends TestCase {

+

+	private static enum Direction { FORWARD, BACKWARD };

+	private static enum Case { SENSITVE, INSENSITVE };

+	private static enum WholeWord { ON, OFF };

+

+	// options

+	private String findString;

+	private Direction direction;

+	private Case caseSensitiveness;

+	private WholeWord wholeWord;

+	private boolean regExSearch;

+

+	// state

+	private AbstractRegExFindReplaceTarget finder;

+	private int selectionStart;

+	private int selectionEnd;

+	private String content;

+

+	private class MyFindReplaceTarget extends AbstractRegExFindReplaceTarget {

+

+		protected int getSelectionStart() {

+			return selectionStart;

+		}

+

+		protected int getSelectionEnd() {

+			return selectionEnd;

+		}

+

+		protected void setSelection(int start, int end) {

+			selectionStart = start;

+			selectionEnd = end;

+		}

+

+		protected CharSequence getDocument() {

+			return content;

+		}

+

+		protected void inDocumentReplaceSelection(CharSequence text) {

+			content =   content.substring(0, selectionStart)

+		              + text

+		              + content.substring(selectionEnd);

+		}

+

+	}

+

+	@Override

+	protected void tearDown() throws Exception {

+		finder = null;

+		findString = null;

+		content = null;

+	}

+

+	private void setUp(String content) {

+		setUp(content, -1, -1);

+	}

+

+	private void setUp(String content, int selectionStart, int selectionEnd) {

+		this.content = content;

+		this.selectionStart = selectionStart;

+		this.selectionEnd = selectionEnd;

+		finder = new MyFindReplaceTarget();

+	}

+

+	private void setFindOptions(String findString,

+			                    Direction direction,

+			                    Case caseSensitve,

+			                    WholeWord wholeWord) {

+		this.findString = findString;

+		this.direction = direction;

+		this.caseSensitiveness = caseSensitve;

+		this.wholeWord = wholeWord;

+		this.regExSearch = false;

+	}

+

+	private void setRegExOptions(String findString,

+                                 Direction direction,

+                                 Case caseSensitve) {

+		this.findString = findString;

+		this.direction = direction;

+		this.caseSensitiveness = caseSensitve;

+		this.wholeWord = WholeWord.OFF;

+		this.regExSearch = true;

+	}

+

+	/**

+	 * @param expected content with the expected selection which is market by

+	 *                 square brackets; example: {code "xyz [selected] ..."}

+	 */

+	private void findAndAssertEquals(String expected) {

+		find();

+		assertEquals(expected);

+	}

+

+	/**

+	 * @param expected content with the expected selection which is market by

+	 *                 square brackets; example: {code "xyz [selected] ..."}

+	 */

+	private void assertEquals(String expected) {

+		int start = expected.indexOf('[');

+		int end = expected.indexOf(']') - 1;

+		assertTrue("selection must marked by square brackets: [...]",

+				   start >= 0 && end >= 0 && end >= start);

+

+		String is = content;

+		if (selectionStart >= 0 && selectionEnd >= 0) {

+			is =   content.substring(0, selectionStart)

+			     + "["

+			     + content.substring(selectionStart, selectionEnd)

+			     + "]"

+			     + content.substring(selectionEnd);

+		}

+		assertEquals(expected, is);

+		CharSequence selection = expected.subSequence(start + 1, end + 1);

+		assertEquals(selection, finder.getSelectionText());

+		assertEquals(start, selectionStart);

+		assertEquals(end, selectionEnd);

+	}

+

+	private boolean find() {

+		int offset = direction == Direction.FORWARD ? selectionEnd : selectionStart;

+		int result = finder.findAndSelect(offset,

+				                          findString,

+				                          direction == Direction.FORWARD,

+				                          caseSensitiveness == Case.SENSITVE,

+				                          wholeWord == WholeWord.ON,

+				                          regExSearch);

+		return result >= 0;

+	}

+

+	public void testSelection() throws Exception {

+		Point selection = null;

+

+		// nothing selected; cursor at the end

+		setUp("aaabbbccc", 9, 9);

+		selection = finder.getSelection();

+		assertEquals("selection offset incorrect", 9, selection.x);

+		assertEquals("selection length incorrect", 0, selection.y);

+		assertEquals("", finder.getSelectionText());

+

+		// selected: 'BB' selected

+		setUp("aaaaaBBcccccc", 5, 7);

+		selection = finder.getSelection();

+		assertEquals("selection offset incorrect", 5, selection.x);

+		assertEquals("selection length incorrect", 2, selection.y);

+		assertEquals("BB", finder.getSelectionText());

+	}

+

+	public void testEnablement() throws Exception {

+		setUp("abc");

+		assertTrue(finder.canPerformFind());

+		assertTrue(finder.isEditable());

+	}

+

+	public void testFind() throws Exception {

+		setUp("aAa.bBb.cCc");

+		setFindOptions("a", Direction.FORWARD, Case.SENSITVE, WholeWord.OFF);

+

+		findAndAssertEquals("[a]Aa.bBb.cCc");

+		findAndAssertEquals("aA[a].bBb.cCc");

+		assertFalse(find());

+		direction = Direction.BACKWARD;

+		findAndAssertEquals("[a]Aa.bBb.cCc");

+		assertFalse(find());

+

+		// in 'Wrap search' offset may be -1 ...

+		setUp("abba", -1, -1);

+		setFindOptions("a", Direction.FORWARD, Case.SENSITVE, WholeWord.OFF);

+		findAndAssertEquals("[a]bba");

+		findAndAssertEquals("abb[a]");

+		assertFalse(find());

+

+        // ... and in backward -1 means find from the end

+		setUp("abba", -1, -1);

+		setFindOptions("a", Direction.BACKWARD, Case.SENSITVE, WholeWord.OFF);

+		findAndAssertEquals("abb[a]");

+		findAndAssertEquals("[a]bba");

+		assertFalse(find());

+	}

+

+	public void testFindWithSpecialChars() throws Exception {

+		// '.' (in regular expression a special char):

+		setUp("aAa.bBb.cCc");

+		setFindOptions(".", Direction.FORWARD, Case.SENSITVE, WholeWord.OFF);

+		findAndAssertEquals("aAa[.]bBb.cCc");

+		findAndAssertEquals("aAa.bBb[.]cCc");

+		assertFalse(find());

+		direction = Direction.BACKWARD;

+		findAndAssertEquals("aAa[.]bBb.cCc");

+		assertFalse(find());

+	}

+

+	public void testFindCaseInsensitive() throws Exception {

+		setUp("ab1 AB1 xxx Ab1 aB1 yyy");

+		setFindOptions("Ab1", Direction.FORWARD, Case.INSENSITVE, WholeWord.OFF);

+		findAndAssertEquals("[ab1] AB1 xxx Ab1 aB1 yyy");

+		findAndAssertEquals("ab1 [AB1] xxx Ab1 aB1 yyy");

+		findAndAssertEquals("ab1 AB1 xxx [Ab1] aB1 yyy");

+		findAndAssertEquals("ab1 AB1 xxx Ab1 [aB1] yyy");

+		assertFalse(find());

+

+		// crosscheck: case-sensitive

+		setFindOptions("Ab1", Direction.BACKWARD, Case.SENSITVE, WholeWord.OFF);

+		findAndAssertEquals("ab1 AB1 xxx [Ab1] aB1 yyy");

+		assertFalse(find());

+	}

+

+	public void testFindWholeWord() throws Exception {

+

+		// including special chars and German umlauts: sharp s = \u00df

+		//                                             ae      = \u00e4

+		setUp("xx aa xx xyx xx-cc a-xx%c \u00e4xx xx\u00df xx");

+		setFindOptions("xx", Direction.FORWARD, Case.SENSITVE, WholeWord.ON);

+		findAndAssertEquals("[xx] aa xx xyx xx-cc a-xx%c \u00e4xx xx\u00df xx");

+		findAndAssertEquals("xx aa [xx] xyx xx-cc a-xx%c \u00e4xx xx\u00df xx");

+		findAndAssertEquals("xx aa xx xyx [xx]-cc a-xx%c \u00e4xx xx\u00df xx");

+		findAndAssertEquals("xx aa xx xyx xx-cc a-[xx]%c \u00e4xx xx\u00df xx");

+		findAndAssertEquals("xx aa xx xyx xx-cc a-xx%c \u00e4xx xx\u00df [xx]");

+		assertFalse(find());

+

+		// crosscheck: backward; 'Whole word' disabled

+		setFindOptions("xx", Direction.BACKWARD, Case.SENSITVE, WholeWord.OFF);

+		findAndAssertEquals("xx aa xx xyx xx-cc a-xx%c \u00e4xx [xx]\u00df xx");

+		findAndAssertEquals("xx aa xx xyx xx-cc a-xx%c \u00e4[xx] xx\u00df xx");

+		findAndAssertEquals("xx aa xx xyx xx-cc a-[xx]%c \u00e4xx xx\u00df xx");

+		findAndAssertEquals("xx aa xx xyx [xx]-cc a-xx%c \u00e4xx xx\u00df xx");

+		findAndAssertEquals("xx aa [xx] xyx xx-cc a-xx%c \u00e4xx xx\u00df xx");

+	}

+

+	public void testFindRegEx() throws Exception {

+		setUp("h2o h5o h42o hoo h234o h3O");

+		setRegExOptions("h[2-4]{1,2}o", Direction.FORWARD, Case.SENSITVE);

+		findAndAssertEquals("[h2o] h5o h42o hoo h234o h3O");

+		findAndAssertEquals("h2o h5o [h42o] hoo h234o h3O");

+		assertFalse(find());

+

+		// case-insensitive

+		caseSensitiveness = Case.INSENSITVE;

+		findAndAssertEquals("h2o h5o h42o hoo h234o [h3O]");

+		assertFalse(find());

+

+		// backward

+		direction = Direction.BACKWARD;

+		caseSensitiveness = Case.SENSITVE;

+		findAndAssertEquals("h2o h5o [h42o] hoo h234o h3O");

+		findAndAssertEquals("[h2o] h5o h42o hoo h234o h3O");

+		assertFalse(find());

+	}

+

+	public void testReplace() throws Exception {

+		setUp("He__o W____!");

+		setFindOptions("__", Direction.FORWARD, Case.SENSITVE, WholeWord.OFF);

+

+		// a) replacement of same length than selection

+		findAndAssertEquals("He[__]o W____!");

+		finder.replaceSelection("ll");

+		assertEquals("He[ll]o W____!");

+

+		// b) replacement shorter than selection

+		findAndAssertEquals("Hello W[__]__!");

+		finder.replaceSelection("o");

+		assertEquals("Hello W[o]__!");

+

+		// c) replacement longer than selection

+		findAndAssertEquals("Hello Wo[__]!");

+		finder.replaceSelection("rld");

+		assertEquals("Hello Wo[rld]!");

+

+		// nothing selected: nothing must be happen

+		setUp("abc", -1, -1);

+		finder.replaceSelection("x");

+		assertEquals(-1, selectionStart);

+		assertEquals(-1, selectionEnd);

+		assertEquals("abc", content);

+	}

+

+	public void testRegExReplace() throws Exception {

+		setUp("Hello World!", 0, 1);

+		setRegExOptions("(.)(l+)", Direction.FORWARD, Case.SENSITVE);

+

+		findAndAssertEquals("H[ell]o World!");

+		finder.replaceSelection("$1_$2", true);

+		assertEquals("H[e_ll]o World!");

+		findAndAssertEquals("He_llo Wo[rl]d!");

+		finder.replaceSelection("$2$1", true);

+	}

+

+	public void testRegExReplaceThrowsIllegalStateException() throws Exception {

+		setUp("Hello World!", 0, 1);

+		setRegExOptions("(.)(l+)", Direction.FORWARD, Case.SENSITVE);

+

+		// 'replace' must preceded by 'findAndSelect',

+		// otherwise -> IllegalStateException

+		setUp("Hello World!", 0, 1);

+		try {

+			finder.replaceSelection("x", true);

+			fail();

+		} catch (IllegalStateException e) {

+			// expected

+		}

+

+		// calling replace twice

+		assertTrue(find());

+		finder.replaceSelection("x", true);

+		replaceAndExpectIllegalStateException();

+

+		// not found

+		assertTrue(find());

+		assertFalse(find());

+		replaceAndExpectIllegalStateException();

+	}

+

+	private void replaceAndExpectIllegalStateException() {

+		try {

+			finder.replaceSelection("x", true);

+			fail();

+		} catch (IllegalStateException e) {

+			// expected

+		}

+	}

+

+	public void testRegExReplaceThrowsPatternSyntaxException()

+			throws Exception {

+		setUp("abcde", 0, 1);

+		setRegExOptions("(.)", Direction.FORWARD, Case.SENSITVE);

+

+		assertTrue(find());

+		replaceAndExpectPatternSyntaxException("single backslash -> \\");

+

+		assertTrue(find());

+		replaceAndExpectPatternSyntaxException("no group 2 -> $2");

+	}

+

+	private void replaceAndExpectPatternSyntaxException(String replacement) {

+		try {

+			finder.replaceSelection(replacement, true);

+			fail(  "Invalid replace pattern '"

+			     + replacement

+			     + "' does not throw PatternSyntaxException.");

+		} catch (PatternSyntaxException e) {

+			// expected

+		}

+	}

+

+}

diff --git a/org.eclipse.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/internal/tests/ResourceTrackerTest.java b/org.eclipse.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/internal/tests/ResourceTrackerTest.java
new file mode 100644
index 0000000..92bfafa
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/internal/tests/ResourceTrackerTest.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2008 John Krasnay and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * 
+ * Contributors:
+ *     John Krasnay - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xml.vex.ui.internal.tests;
+
+import junit.framework.TestCase;
+
+/**
+ * Test the ResourceTracker class.
+ */
+public class ResourceTrackerTest extends TestCase {
+
+	public void testAll() throws Exception {
+		    // as a placeholder, always return "passed", until real tests filled in
+			assertTrue(true);
+	}
+}
diff --git a/org.eclipse.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/tests/IconTest.java b/org.eclipse.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/tests/IconTest.java
new file mode 100644
index 0000000..4051e7a
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/tests/IconTest.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Holger Voormann and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Holger Voormann - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xml.vex.ui.tests;
+
+import org.eclipse.wst.xml.vex.ui.internal.Icon;
+
+import junit.framework.TestCase;
+
+public class IconTest extends TestCase {
+
+	public void testWhetherAllIconsExist() throws Exception {
+		for (Icon icon : Icon.values()) {
+			assertNotNull(Icon.get(icon));
+		}
+	}
+
+}
diff --git a/org.eclipse.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/tests/VexUiTestSuite.java b/org.eclipse.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/tests/VexUiTestSuite.java
new file mode 100644
index 0000000..45051d2
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/src/org/eclipse/wst/xml/vex/ui/tests/VexUiTestSuite.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Holger Voormann and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     Holger Voormann - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.wst.xml.vex.ui.tests;
+
+import junit.framework.JUnit4TestAdapter;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import org.eclipse.wst.xml.vex.ui.internal.config.tests.ConfigLoaderJobTest;
+import org.eclipse.wst.xml.vex.ui.internal.config.tests.ConfigurationRegistryTest;
+import org.eclipse.wst.xml.vex.ui.internal.editor.tests.FindReplaceTargetTest;
+import org.eclipse.wst.xml.vex.ui.internal.tests.ResourceTrackerTest;
+
+public class VexUiTestSuite extends TestSuite {
+
+	public static Test suite() {
+		return new VexUiTestSuite();
+	}
+
+	public VexUiTestSuite() {
+		super("Vex UI Tests"); //$NON-NLS-1$
+		addTest(new JUnit4TestAdapter(ConfigLoaderJobTest.class));
+		addTest(new JUnit4TestAdapter(ConfigurationRegistryTest.class));
+		addTestSuite(IconTest.class);
+		addTestSuite(FindReplaceTargetTest.class);
+		addTestSuite(ResourceTrackerTest.class);
+	}
+
+}
diff --git a/org.eclipse.vex.ui.tests/testdata/test.css b/org.eclipse.vex.ui.tests/testdata/test.css
new file mode 100644
index 0000000..9a83031
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/testdata/test.css
@@ -0,0 +1,53 @@
+
+html {
+  display: block;
+}
+
+body {
+  display: block;
+}
+
+p {
+  display: block;
+}
+
+block {
+  display: block;
+}
+
+pre {
+  display: block;
+  white-space: pre;
+}
+
+
+/* Styles for positioning tests */
+root {
+  border: 3px 7px 11px 13px;
+  padding: 17px 19px 23px 29px;
+}
+
+small {
+  border-width: 1px 2px 3px 4px;
+  border-style: solid;
+  margin: 100px 200px 300px 400px;
+  padding: 10px 20px 30px 40px;
+  display: block;
+}
+
+medium {
+  border-width: 2px 4px 6px 8px;
+  border-style: solid;
+  margin: 200px 400px 600px 800px;
+  padding: 20px 40px 60px 80px;
+  display: block;
+}
+
+large {
+  border-width: 3px 6px 9px 12px;
+  border-style: solid;
+  margin: 300px 600px 900px 1200px;
+  padding: 30px 60px 90px 120px;
+  display: block;
+}
+
diff --git a/org.eclipse.vex.ui.tests/testdata/test.dtd b/org.eclipse.vex.ui.tests/testdata/test.dtd
new file mode 100644
index 0000000..f246a88
--- /dev/null
+++ b/org.eclipse.vex.ui.tests/testdata/test.dtd
@@ -0,0 +1,10 @@
+<!ELEMENT any ANY>
+<!ELEMENT empty EMPTY>
+<!ELEMENT section (title?, para+)>
+<!ELEMENT para (#PCDATA | emphasis)*>
+<!ELEMENT title (#PCDATA)>
+<!ELEMENT emphasis (#PCDATA)>
+
+<!-- a dummy attribute, just to make sure attribute def serialization is OK -->
+<!ATTLIST section
+	name	CDATA	#IMPLIED>
\ No newline at end of file