svn commit: r17979 - trunk/src/argouml-app: src/org/argouml/profile src/org/argouml/profile/internal tests/org/argouml tests/org/argouml/kernel tests/org/argouml/profile tests/org/argouml/profile/internal
Luis Sergio Oliveira <[email protected]>
| Newsgroups | gmane.comp.lang.uml.argouml.cvs |
|---|---|
| Message-ID | <[email protected]> |
Author: euluis
Date: 2010-02-10 17:24:27-0800
New Revision: 17979
Added:
trunk/src/argouml-app/src/org/argouml/profile/internal/DependencyChecker.java (contents, props changed)
trunk/src/argouml-app/src/org/argouml/profile/internal/DependencyResolver.java (contents, props changed)
trunk/src/argouml-app/tests/org/argouml/TestFileHelper.java (contents, props changed)
trunk/src/argouml-app/tests/org/argouml/profile/internal/TestDependencyResolver.java (contents, props changed)
Modified:
trunk/src/argouml-app/src/org/argouml/profile/UserProfileReference.java
trunk/src/argouml-app/src/org/argouml/profile/internal/ProfileManagerImpl.java
trunk/src/argouml-app/tests/org/argouml/FileHelper.java
trunk/src/argouml-app/tests/org/argouml/kernel/TestProjectWithProfiles.java
trunk/src/argouml-app/tests/org/argouml/profile/ProfileMother.java
trunk/src/argouml-app/tests/org/argouml/profile/TestProfileMother.java
trunk/src/argouml-app/tests/org/argouml/profile/TestUserDefinedProfile.java
trunk/src/argouml-app/tests/org/argouml/profile/internal/TestProfileManagerImpl.java
Log:
issue 4997: implemented reactive and smart dependency resolution of user defined profiles
Modified: trunk/src/argouml-app/src/org/argouml/profile/UserProfileReference.java
Url: http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-app/src/org/argouml/profile/UserProfileReference.java?view=diff&pathrev=17979&r1=17978&r2=17979
==============================================================================
--- trunk/src/argouml-app/src/org/argouml/profile/UserProfileReference.java (original)
+++ trunk/src/argouml-app/src/org/argouml/profile/UserProfileReference.java 2010-02-10 17:24:27-0800
@@ -1,6 +1,6 @@
/* $Id$
*****************************************************************************
- * Copyright (c) 2009 Contributors - see below
+ * Copyright (c) 2009-2010 Contributors - see below
* 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
@@ -49,7 +49,11 @@
*/
public class UserProfileReference extends ProfileReference {
- static final String DEFAULT_USER_PROFILE_BASE_URL =
+ /**
+ * The default user profile base URL, which will be used if no explicit URL
+ * is specified.
+ */
+ public static final String DEFAULT_USER_PROFILE_BASE_URL =
"http://argouml.org/user-profiles/";
/**
@@ -76,5 +80,4 @@
super(path,
new URL(DEFAULT_USER_PROFILE_BASE_URL + new File(path).getName()));
}
-
}
Added: trunk/src/argouml-app/src/org/argouml/profile/internal/DependencyChecker.java
Url: http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-app/src/org/argouml/profile/internal/DependencyChecker.java?view=markup&pathrev=17979
==============================================================================
--- (empty file)
+++ trunk/src/argouml-app/src/org/argouml/profile/internal/DependencyChecker.java 2010-02-10 17:24:27-0800
@@ -0,0 +1,33 @@
+/* $Id$
+ *****************************************************************************
+ * Copyright (c) 2010 Contributors - see below
+ * 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:
+ * euluis
+ *****************************************************************************
+ */
+
+package org.argouml.profile.internal;
+
+/**
+ * An interface to be used to check if all dependencies of items are resolved
+ * or not.
+ * @author Luis Sergio Oliveira (euluis)
+ * @param <T> the type of the items for which the dependencies are to be
+ * checked.
+ */
+interface DependencyChecker<T> {
+ /**
+ * Check if all dependencies of item are resolved.
+ *
+ * @param item the item for which to check if the dependencies are
+ * resolved.
+ * @return true if the check if item dependencies are all resolved is
+ * successful.
+ */
+ boolean check(T item);
+}
Added: trunk/src/argouml-app/src/org/argouml/profile/internal/DependencyResolver.java
Url: http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-app/src/org/argouml/profile/internal/DependencyResolver.java?view=markup&pathrev=17979
==============================================================================
--- (empty file)
+++ trunk/src/argouml-app/src/org/argouml/profile/internal/DependencyResolver.java 2010-02-10 17:24:27-0800
@@ -0,0 +1,114 @@
+/* $Id$
+ *****************************************************************************
+ * Copyright (c) 2010 Contributors - see below
+ * 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:
+ * euluis
+ *****************************************************************************
+ */
+
+package org.argouml.profile.internal;
+
+import java.util.HashSet;
+import java.util.Collection;
+
+import org.apache.log4j.Logger;
+
+/**
+ * A dependency resolver for items of type T. It implements a state-full
+ * dependency resolution algorithm.
+ *
+ * @author Luis Sergio Oliveira (euluis)
+ * @param <T> the type of items for which dependencies will be resolved.
+ */
+class DependencyResolver<T> {
+
+ private static final Logger LOG = Logger.getLogger(
+ DependencyResolver.class);
+
+ private DependencyChecker<T> checker;
+ private Collection<T> unresolvedItems;
+
+ /**
+ * Create a dependency resolver and initialize it with the associated
+ * dependency checker.
+ *
+ * @param checker the object that will be invoked to check if for a certain
+ * item all dependencies are resolved.
+ */
+ DependencyResolver(DependencyChecker<T> checker) {
+ this.checker = checker;
+ unresolvedItems = new HashSet<T>();
+ }
+
+ /**
+ * Attempt to resolve the dependencies of the items already handed over to
+ * the resolver instance.
+ */
+ void resolve() {
+ if (unresolvedItems.isEmpty()) {
+ return;
+ }
+ resolve(new HashSet<T>());
+ }
+
+ /**
+ * @param items additional items to resolve.
+ */
+ void resolve(Collection<T> items) {
+ if (unresolvedItems.isEmpty() && items.isEmpty()) {
+ return;
+ }
+ Collection<T> allUnresolvedItems = new HashSet<T>();
+ allUnresolvedItems.addAll(items);
+ allUnresolvedItems.addAll(unresolvedItems);
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(items2Msg("Attempt to resolve the following items:",
+ allUnresolvedItems));
+ }
+ Collection<T> resolved = internalResolve(allUnresolvedItems);
+ allUnresolvedItems.removeAll(resolved);
+ unresolvedItems.addAll(allUnresolvedItems);
+ if (!unresolvedItems.isEmpty()) {
+ LOG.warn(items2Msg(
+ "The following items were left unresolved after attempt:\n",
+ unresolvedItems));
+ }
+ }
+
+ private String items2Msg(String preface, Collection<T> items) {
+ StringBuffer msg = new StringBuffer(preface);
+ for (T item : items) {
+ msg.append("\t");
+ msg.append(item.toString());
+ msg.append("\n");
+ }
+ return msg.toString();
+ }
+
+ /**
+ * Recursively resolve all dependencies. Stops when an iteration through
+ * all unresolved items didn't manage to resolve any.
+ *
+ * @param items items to resolve.
+ * @return the items that were resolved.
+ */
+ private Collection<T> internalResolve(Collection<T> items) {
+ Collection<T> resolved = new HashSet<T>();
+ for (T item : items) {
+ if (checker.check(item)) {
+ resolved.add(item);
+ }
+ }
+ HashSet<T> toResolveItems = new HashSet<T>(items);
+ toResolveItems.removeAll(resolved);
+ if (!resolved.isEmpty()) {
+ resolved.addAll(internalResolve(toResolveItems));
+ }
+ return resolved;
+ }
+}
Modified: trunk/src/argouml-app/src/org/argouml/profile/internal/ProfileManagerImpl.java
Url: http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-app/src/org/argouml/profile/internal/ProfileManagerImpl.java?view=diff&pathrev=17979&r1=17978&r2=17979
==============================================================================
--- trunk/src/argouml-app/src/org/argouml/profile/internal/ProfileManagerImpl.java (original)
+++ trunk/src/argouml-app/src/org/argouml/profile/internal/ProfileManagerImpl.java 2010-02-10 17:24:27-0800
@@ -104,6 +104,7 @@
private ProfileCodeGeneration profileCodeGeneration;
+ private DependencyResolver<File> resolver;
/**
* Constructor - includes initialization of built-in default profiles.
@@ -117,14 +118,14 @@
profileCodeGeneration = new ProfileCodeGeneration(
profileGoodPractices);
- registerProfile(profileUML);
+ registerProfileInternal(profileUML);
addToDefaultProfiles(profileUML);
// the UML Profile is always present and default
// register the built-in profiles
- registerProfile(profileGoodPractices);
- registerProfile(profileCodeGeneration);
- registerProfile(new ProfileMeta());
+ registerProfileInternal(profileGoodPractices);
+ registerProfileInternal(profileCodeGeneration);
+ registerProfileInternal(new ProfileMeta());
} catch (ProfileException e) {
// TODO: Why is this throwing a generic runtime exception?!?!
@@ -132,14 +133,37 @@
} finally {
disableConfigurationUpdate = false;
}
-
+ createUserDefinedProfilesDependencyResolver();
loadDirectoriesFromConfiguration();
-
refreshRegisteredProfiles();
-
loadDefaultProfilesfromConfiguration();
}
+ private void createUserDefinedProfilesDependencyResolver() {
+ final ProfileManager profileManager = this;
+ DependencyChecker<File> checker = new DependencyChecker<File>() {
+ public boolean check(File file) {
+ boolean found = findUserDefinedProfile(file) != null;
+ if (!found) {
+ UserDefinedProfile udp = null;
+ try {
+ udp = new UserDefinedProfile(file, profileManager);
+ registerProfileInternal(udp);
+ found = true;
+ LOG.debug("UserDefinedProfile for file "
+ + file.getAbsolutePath() + " registered.");
+ } catch (ProfileException e) {
+ // if an exception is raised file is unusable
+ LOG.info("Failed to load user defined profile "
+ + file.getAbsolutePath() + ".", e);
+ }
+ }
+ return found;
+ }
+ };
+ resolver = new DependencyResolver<File>(checker);
+ }
+
private void loadDefaultProfilesfromConfiguration() {
if (!disableConfigurationUpdate) {
disableConfigurationUpdate = true;
@@ -147,13 +171,10 @@
String defaultProfilesList = Configuration
.getString(KEY_DEFAULT_PROFILES);
if (defaultProfilesList.equals("")) {
- // if the list does not exist
- // add the Java profile and the code generation and good
- // practices profiles as default
-
+ // if the list does not exist add the code generation and
+ // good practices profiles as default
addToDefaultProfiles(profileGoodPractices);
addToDefaultProfiles(profileCodeGeneration);
-
} else {
StringTokenizer tokenizer = new StringTokenizer(
defaultProfilesList, DIRECTORY_SEPARATOR, false);
@@ -173,7 +194,7 @@
if (p == null) {
try {
p = new UserDefinedProfile(file, this);
- registerProfile(p);
+ registerProfileInternal(p);
} catch (ProfileException e) {
LOG.error("Error loading profile: " + file,
e);
@@ -190,7 +211,6 @@
String profileIdentifier = desc.substring(1);
p = lookForRegisteredProfile(profileIdentifier);
}
-
if (p != null) {
addToDefaultProfiles(p);
}
@@ -203,7 +223,6 @@
private void updateDefaultProfilesConfiguration() {
if (!disableConfigurationUpdate) {
StringBuffer buf = new StringBuffer();
-
for (Profile p : defaultProfiles) {
if (p instanceof UserDefinedProfile) {
buf.append("U"
@@ -212,70 +231,71 @@
} else {
buf.append("C" + p.getProfileIdentifier());
}
-
buf.append(DIRECTORY_SEPARATOR);
}
-
Configuration.setString(KEY_DEFAULT_PROFILES, buf.toString());
}
}
private void loadDirectoriesFromConfiguration() {
disableConfigurationUpdate = true;
-
StringTokenizer tokenizer =
new StringTokenizer(
Configuration.getString(KEY_DEFAULT_DIRECTORIES),
DIRECTORY_SEPARATOR, false);
-
while (tokenizer.hasMoreTokens()) {
searchDirectories.add(tokenizer.nextToken());
}
-
disableConfigurationUpdate = false;
}
private void updateSearchDirectoriesConfiguration() {
if (!disableConfigurationUpdate) {
StringBuffer buf = new StringBuffer();
-
for (String s : searchDirectories) {
buf.append(s).append(DIRECTORY_SEPARATOR);
}
-
Configuration.setString(KEY_DEFAULT_DIRECTORIES, buf.toString());
}
}
-
public List<Profile> getRegisteredProfiles() {
return profiles;
}
-
- public void registerProfile(Profile p) {
+ public void registerProfile(Profile p) {
+ if (registerProfileInternal(p)) {
+ // this profile could have not been loaded when
+ // the default profile configuration
+ // was loaded at first, so we need to do it again
+ loadDefaultProfilesfromConfiguration();
+ }
+ resolver.resolve();
+ }
+
+ /**
+ * @param p the profile to register.
+ * @return true if there should be an attempt to load the default profiles
+ * from the configuration.
+ */
+ private boolean registerProfileInternal(Profile p) {
+ boolean loadDefaultProfilesFromConfiguration = false;
if (p != null && !profiles.contains(p)) {
if (p instanceof UserDefinedProfile
|| getProfileForClass(p.getClass().getName()) == null) {
+ loadDefaultProfilesFromConfiguration = true;
profiles.add(p);
-
for (Critic critic : p.getCritics()) {
for (Object meta : critic.getCriticizedDesignMaterials()) {
Agency.register(critic, meta);
}
-
critic.setEnabled(false);
}
-
- // this profile could have not been loaded when
- // the default profile configuration
- // was loaded at first, so we need to do it again
- loadDefaultProfilesfromConfiguration();
}
}
+ return loadDefaultProfilesFromConfiguration;
}
-
public void removeProfile(Profile p) {
if (p != null && p != profileUML) {
profiles.remove(p);
@@ -292,7 +312,6 @@
}
}
-
private static final String OLD_PROFILE_PACKAGE = "org.argouml.uml.profile";
private static final String NEW_PROFILE_PACKAGE =
@@ -320,7 +339,6 @@
return found;
}
-
public void addToDefaultProfiles(Profile p) {
if (p != null && profiles.contains(p)
&& !defaultProfiles.contains(p)) {
@@ -329,12 +347,10 @@
}
}
-
public List<Profile> getDefaultProfiles() {
return Collections.unmodifiableList(defaultProfiles);
}
-
public void removeFromDefaultProfiles(Profile p) {
if (p != null && p != profileUML && profiles.contains(p)) {
defaultProfiles.remove(p);
@@ -342,7 +358,6 @@
}
}
-
public void addSearchPathDirectory(String path) {
if (path != null && !searchDirectories.contains(path)) {
searchDirectories.add(path);
@@ -355,12 +370,10 @@
}
}
-
public List<String> getSearchPathDirectories() {
return Collections.unmodifiableList(searchDirectories);
}
-
public void removeSearchPathDirectory(String path) {
if (path != null) {
searchDirectories.remove(path);
@@ -374,48 +387,29 @@
}
public void refreshRegisteredProfiles() {
-
ArrayList<File> dirs = new ArrayList<File>();
-
for (String dirName : searchDirectories) {
File dir = new File(dirName);
if (dir.exists()) {
dirs.add(dir);
}
}
-
if (!dirs.isEmpty()) {
// TODO: Allow .zargo as profile as well?
- File[] fileArray = new File[dirs.size()];
- for (int i = 0; i < dirs.size(); i++) {
- fileArray[i] = dirs.get(i);
- }
- List<File> dirList
- = UserDefinedProfileHelper.getFileList(fileArray);
- for (File file : dirList) {
- boolean found =
- findUserDefinedProfile(file) != null;
- if (!found) {
- UserDefinedProfile udp = null;
- try {
- udp = new UserDefinedProfile(file, this);
- registerProfile(udp);
- } catch (ProfileException e) {
- // if an exception is raised file is unusable
- LOG.warn("Failed to load user defined profile "
- + file.getAbsolutePath() + ".", e);
- }
- }
- }
+ List<File> profileFiles = UserDefinedProfileHelper.getFileList(
+ dirs.toArray(new File[0]));
+ loadProfiles(profileFiles);
}
}
+ void loadProfiles(List<File> profileFiles) {
+ resolver.resolve(profileFiles);
+ }
+
private Profile findUserDefinedProfile(File file) {
-
for (Profile p : profiles) {
if (p instanceof UserDefinedProfile) {
UserDefinedProfile udp = (UserDefinedProfile) p;
-
if (file.equals(udp.getModelFile())) {
return udp;
}
@@ -424,7 +418,6 @@
return null;
}
-
public Profile getUMLProfile() {
return profileUML;
}
@@ -455,7 +448,6 @@
Configuration.setBoolean(c.getCriticKey(), false);
}
}
-
for (Profile p : pc.getProfiles()) {
for (Critic c : p.getCritics()) {
c.setEnabled(true);
@@ -463,5 +455,4 @@
}
}
}
-
}
Modified: trunk/src/argouml-app/tests/org/argouml/FileHelper.java
Url: http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-app/tests/org/argouml/FileHelper.java?view=diff&pathrev=17979&r1=17978&r2=17979
==============================================================================
--- trunk/src/argouml-app/tests/org/argouml/FileHelper.java (original)
+++ trunk/src/argouml-app/tests/org/argouml/FileHelper.java 2010-02-10 17:24:27-0800
@@ -1,6 +1,6 @@
/* $Id$
*****************************************************************************
- * Copyright (c) 2009 Contributors - see below
+ * Copyright (c) 2009-2010 Contributors - see below
* 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
@@ -39,6 +39,9 @@
package org.argouml;
import java.io.File;
+import java.io.IOException;
+
+import junit.framework.TestCase;
/**
* Helper for common File related operations used in automated tests.
@@ -46,39 +49,78 @@
* @author Luis Sergio Oliveira (euluis)
*/
public class FileHelper {
-
+
/**
- * System temporary directory property name.
+ * Default temporary directory prefix.
*/
- public static final String SYSPROPNAME_TMPDIR = "java.io.tmpdir";
-
-
- public static File getTmpDir() {
- return new File(System.getProperty(SYSPROPNAME_TMPDIR));
- }
+ static final String DEFAULT_TEMP_DIR_PREFIX = "prefix";
/**
- * Setup a directory with the given name for the caller test.
+ * Setup a directory with the given name prefix for the caller test.
*
- * @param dirName the directory to be created in the system temporary dir
- * @return the created directory
+ * @param dirNamePrefix the prefix of the directory name to be created in
+ * the system temporary directory.
+ * @return the created directory.
+ * @throws IOException if the directory creation fails.
*/
- public static File setUpDir4Test(String dirName) {
- File generationDir = new File(getTmpDir(), dirName);
- generationDir.mkdirs();
- return generationDir;
+ public static File setUpDir4Test(String dirNamePrefix) throws IOException {
+ return createTempDirectory(dirNamePrefix);
}
- public static File setUpDir4Test(Class<?> testClass) {
+ /**
+ * @param testClass the {@link TestCase} class for which to create a
+ * directory.
+ * @return the created directory.
+ * @throws IOException if the directory creation fails.
+ */
+ public static File setUpDir4Test(Class<?> testClass) throws IOException {
String name = testClass.getPackage().getName() + "."
+ testClass.getSimpleName();
return setUpDir4Test(name);
}
- public static void deleteDir(File dir) {
- if (dir != null && dir.exists()) {
- dir.delete();
+ /**
+ * Delete fileOrDirectory with the bonus of recursively deleting children
+ * of fileOrDirectory if it is a directory.
+ *
+ * @param fileOrDirectory the file or directory to be deleted.
+ */
+ public static void delete(File fileOrDirectory) {
+ if (fileOrDirectory != null && fileOrDirectory.exists()) {
+ if (fileOrDirectory.isDirectory()) {
+ File[] children = fileOrDirectory.listFiles();
+ for (File child : children) {
+ delete(child);
+ }
+ }
+ fileOrDirectory.delete();
}
}
+ /**
+ * @param prefix the prefix of the directory name.
+ * @return a {@link File} associated to a newly created directory which is
+ * contained within the system temporary directory.
+ * @throws IOException When the creation of the directory throws.
+ */
+ public static File createTempDirectory(String prefix) throws IOException {
+ File tempFile = File.createTempFile(prefix, "");
+ String absolutePath = tempFile.getAbsolutePath();
+ tempFile.delete();
+ tempFile.mkdir();
+ return new File(absolutePath);
+ }
+
+ /**
+ * Create a unique temporary directory contained within the system
+ * temporary directory.
+ *
+ * @return a {@link File} associated to a newly created directory which is
+ * contained within the system temporary directory and with prefix
+ * {@link FileHelper#DEFAULT_TEMP_DIR_PREFIX}.
+ * @throws IOException When the creation of the directory throws.
+ */
+ public static File createTempDirectory() throws IOException {
+ return createTempDirectory(DEFAULT_TEMP_DIR_PREFIX);
+ }
}
Added: trunk/src/argouml-app/tests/org/argouml/TestFileHelper.java
Url: http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-app/tests/org/argouml/TestFileHelper.java?view=markup&pathrev=17979
==============================================================================
--- (empty file)
+++ trunk/src/argouml-app/tests/org/argouml/TestFileHelper.java 2010-02-10 17:24:27-0800
@@ -0,0 +1,39 @@
+/* $Id$
+ *****************************************************************************
+ * Copyright (c) 2010 Contributors - see below
+ * 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:
+ * euluis
+ *****************************************************************************
+ */
+
+package org.argouml;
+
+import java.io.File;
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+/**
+ * Integration tests for the FileHelper.
+ * @author Luis Sergio Oliveira (euluis)
+ */
+public class TestFileHelper extends TestCase {
+
+ /**
+ * Test {@link FileHelper#createTempDirectory()} with the directory not
+ * existing before.
+ * @throws IOException if the creation of files or directories throws.
+ */
+ public void testCreateTempDirectory() throws IOException {
+ File tmpDir = FileHelper.createTempDirectory();
+ tmpDir.deleteOnExit();
+ assertTrue("The directory should exist.", tmpDir.exists());
+ assertTrue("The directory isn't a directory.", tmpDir.isDirectory());
+ assertTrue("The directory is writable.", tmpDir.canWrite());
+ }
+}
Modified: trunk/src/argouml-app/tests/org/argouml/kernel/TestProjectWithProfiles.java
Url: http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-app/tests/org/argouml/kernel/TestProjectWithProfiles.java?view=diff&pathrev=17979&r1=17978&r2=17979
==============================================================================
--- trunk/src/argouml-app/tests/org/argouml/kernel/TestProjectWithProfiles.java (original)
+++ trunk/src/argouml-app/tests/org/argouml/kernel/TestProjectWithProfiles.java 2010-02-10 17:24:27-0800
@@ -83,6 +83,7 @@
/*
* @see junit.framework.TestCase#setUp()
*/
+ @SuppressWarnings("unchecked")
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -97,13 +98,13 @@
initMethod.invoke(null);
assertNotNull(ApplicationVersion.getVersion());
}
- String testCaseDirName = getClass().getPackage().getName();
- testCaseDir = FileHelper.setUpDir4Test(testCaseDirName);
+ String testCaseDirNamePrefix = getClass().getPackage().getName();
+ testCaseDir = FileHelper.setUpDir4Test(testCaseDirNamePrefix);
}
@Override
protected void tearDown() throws Exception {
- FileHelper.deleteDir(testCaseDir);
+ FileHelper.delete(testCaseDir);
super.tearDown();
}
Modified: trunk/src/argouml-app/tests/org/argouml/profile/ProfileMother.java
Url: http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-app/tests/org/argouml/profile/ProfileMother.java?view=diff&pathrev=17979&r1=17978&r2=17979
==============================================================================
--- trunk/src/argouml-app/tests/org/argouml/profile/ProfileMother.java (original)
+++ trunk/src/argouml-app/tests/org/argouml/profile/ProfileMother.java 2010-02-10 17:24:27-0800
@@ -1,6 +1,6 @@
/* $Id$
*****************************************************************************
- * Copyright (c) 2009 Contributors - see below
+ * Copyright (c) 2009-2010 Contributors - see below
* 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
@@ -8,6 +8,7 @@
*
* Contributors:
* maurelio1234
+ * euluis
*****************************************************************************
*
* Some portions of this file was previously release using the BSD License:
@@ -49,14 +50,19 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
import junit.framework.TestCase;
import org.apache.log4j.Logger;
+import org.argouml.FileHelper;
import org.argouml.model.Model;
+import org.argouml.model.UmlException;
+import org.argouml.model.XmiReader;
import org.argouml.model.XmiWriter;
import org.argouml.persistence.UmlFilePersister;
+import org.xml.sax.InputSource;
/**
* Based on the
@@ -66,7 +72,24 @@
* @author Luis Sergio Oliveira (euluis)
*/
public class ProfileMother {
-
+
+ /**
+ * This interface implementors can be used to create dependencies between
+ * profiles.
+ * @author Luis Sergio Oliveira (euluis)
+ */
+ public interface DependencyCreator {
+ /**
+ * Creates a dependency between dependentProfile and
+ * profileFromWhichDepends.
+ * @param profileFromWhichDepends the profile model to which
+ * dependentProfile will depend.
+ * @param dependentProfile the profile model that will be dependent
+ * of profileFromWhichDepends.
+ */
+ void create(Object profileFromWhichDepends, Object dependentProfile);
+ }
+
private static final Logger LOG = Logger.getLogger(ProfileMother.class);
/**
@@ -77,20 +100,34 @@
* "st" the example stereotype name.
*/
public static final String STEREOTYPE_NAME_ST = "st";
+
+ private final String DEFAULT_SIMPLE_PROFILE_NAME = "SimpleProfile";
/**
- * Create a simple profile model with a class named "foo" and with a
- * stereotype named "st".
+ * Create a simple profile model with name {@link ProfileMother#DEFAULT_SIMPLE_PROFILE_NAME}
+ * with a class named "foo" and with a stereotype named
+ * {@link ProfileMother#STEREOTYPE_NAME_ST}.
*
* @return the profile model.
*/
public Object createSimpleProfileModel() {
- Object model = getModelManagementFactory().createModel();
- Object profileStereotype = getProfileStereotype();
- getCoreHelper().addStereotype(model, profileStereotype);
+ return createSimpleProfileModel(DEFAULT_SIMPLE_PROFILE_NAME);
+ }
+
+ /**
+ * Create a simple profile model with name profileName,
+ * with a class named "foo" and with a stereotype named
+ * {@link ProfileMother#STEREOTYPE_NAME_ST}.
+ *
+ * @param profileName the name that the created profile shall have.
+ * @return the profile model.
+ */
+ public Object createSimpleProfileModel(String profileName) {
+ Object model = getModelManagementFactory().createProfile();
Object fooClass = Model.getCoreFactory().buildClass("foo", model);
getExtensionMechanismsFactory().buildStereotype(fooClass,
STEREOTYPE_NAME_ST, model);
+ getCoreHelper().setName(model, profileName);
return model;
}
@@ -151,4 +188,89 @@
}
}
+ /**
+ * Create a XMI file that stores a UML profile which depends via XMI
+ * of the profile stored in profileFromWhichDependsFile.
+ * @param profileFromWhichDependsFile a {@link File} associated to the file
+ * which contains the XMI for the profile from which the created
+ * profile will depend.
+ * @param dependencyCreator the object that will be called to actually
+ * create the dependency between the new model and the other.
+ * @param profilesDir the directory within which the profile XMI file that
+ * will be created is stored.
+ * @param dependentProfileFilenamePrefix the file name prefix for the file
+ * that will contain the XMI of the created profile.
+ * @return the {@link File} associated to the file where the created
+ * dependent profile is stored (XMI).
+ * @throws IOException if the new profile file creation fails.
+ * @throws UmlException if the model subsystem throws.
+ */
+ public File createXmiDependentProfile(File profileFromWhichDependsFile,
+ DependencyCreator dependencyCreator,
+ File profilesDir, String dependentProfileFilenamePrefix)
+ throws IOException, UmlException {
+ XmiReader xmiReader = Model.getXmiReader();
+ xmiReader.addSearchPath(profileFromWhichDependsFile.getParent());
+ InputSource pIs = new InputSource(
+ profileFromWhichDependsFile.toURI().toURL().toExternalForm());
+ pIs.setPublicId(UserProfileReference.DEFAULT_USER_PROFILE_BASE_URL
+ + profileFromWhichDependsFile.getName());
+ Collection profileFromWhichDependsModelTopElements = xmiReader.parse(
+ pIs, true);
+ Object dependentProfile = getModelManagementFactory().createProfile();
+ Object profileFromWhichDependsModel = null;
+ for (Object topElement : profileFromWhichDependsModelTopElements) {
+ if (DEFAULT_SIMPLE_PROFILE_NAME.equals(
+ getFacade().getName(topElement))) {
+ profileFromWhichDependsModel = topElement;
+ break;
+ }
+ }
+ dependencyCreator.create(profileFromWhichDependsModel,
+ dependentProfile);
+ File dependentProfileFile = File.createTempFile(
+ dependentProfileFilenamePrefix, ".xmi", profilesDir);
+ saveProfileModel(dependentProfile, dependentProfileFile);
+ Model.getUmlFactory().deleteExtent(dependentProfile);
+ xmiReader.removeSearchPath(profileFromWhichDependsFile.getParent());
+ return dependentProfileFile;
+ }
+
+ /**
+ * Creates two profiles with one depending of the other. Saves the two
+ * profiles in a temporary directory and returns the associated
+ * {@link File Files}, being that the second XMI file depends on the first.
+ * @return A list of two files, the second File contains an XMI that
+ * depends of the first.
+ * @throws IOException if file IO causes errors.
+ * @throws UmlException if the manipulation of models causes errors.
+ */
+ public List<File> createProfileFilePairWithSecondDependingOnFirstThroughXmi()
+ throws IOException, UmlException {
+ File profilesDir = FileHelper.createTempDirectory();
+ final File baseFile = File.createTempFile(
+ "baseProfile", ".xmi", profilesDir);
+ Object model = createSimpleProfileModel();
+ saveProfileModel(model, baseFile);
+ Model.getUmlFactory().deleteExtent(model);
+ ProfileMother.DependencyCreator dependencyCreator =
+ new ProfileMother.DependencyCreator() {
+ public void create(Object profileFromWhichDepends,
+ Object dependentProfile) {
+ Object theClass = Model.getCoreFactory().buildClass("DasClazz",
+ dependentProfile);
+ Collection stereotypes = getFacade().getStereotypes(
+ profileFromWhichDepends);
+ assert stereotypes.size() >= 1: "";
+ Object stereotype = stereotypes.iterator().next();
+ Model.getCoreHelper().addStereotype(theClass, stereotype);
+ }
+ };
+ String dependentProfileFilenamePrefix = "dependentProfile";
+ final File dependentFile = createXmiDependentProfile(
+ baseFile, dependencyCreator, profilesDir,
+ dependentProfileFilenamePrefix);
+ return new ArrayList<File>() { { add(baseFile); add(dependentFile); }
+ };
+ }
}
Modified: trunk/src/argouml-app/tests/org/argouml/profile/TestProfileMother.java
Url: http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-app/tests/org/argouml/profile/TestProfileMother.java?view=diff&pathrev=17979&r1=17978&r2=17979
==============================================================================
--- trunk/src/argouml-app/tests/org/argouml/profile/TestProfileMother.java (original)
+++ trunk/src/argouml-app/tests/org/argouml/profile/TestProfileMother.java 2010-02-10 17:24:27-0800
@@ -1,6 +1,6 @@
/* $Id$
*****************************************************************************
- * Copyright (c) 2009 Contributors - see below
+ * Copyright (c) 2009-2010 Contributors - see below
* 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
@@ -8,6 +8,7 @@
*
* Contributors:
* maurelio1234
+ * euluis
*****************************************************************************
*
* Some portions of this file was previously release using the BSD License:
@@ -41,23 +42,32 @@
import static org.argouml.model.Model.getExtensionMechanismsHelper;
import static org.argouml.model.Model.getFacade;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
+import org.argouml.FileHelper;
import org.argouml.model.InitializeModel;
import org.argouml.model.Model;
+import org.argouml.model.UmlException;
+import org.argouml.model.XmiReader;
+import org.xml.sax.InputSource;
+import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
/**
+ * Integration tests for the {@link ProfileMother} class.
*
* @author Luis Sergio Oliveira (euluis)
*/
public class TestProfileMother extends TestCase {
private ProfileMother mother;
- private File testDir;
@Override
protected void setUp() throws Exception {
@@ -65,6 +75,9 @@
mother = new ProfileMother();
}
+ /**
+ * Test the creation of a profile model.
+ */
public void testCreateProfileModel() {
Object model = mother.createSimpleProfileModel();
assertNotNull(model);
@@ -74,7 +87,11 @@
getFacade().getName(profileStereotypes.iterator().next()));
}
- public void testCreateSimpleProfileModel() throws Exception {
+ /**
+ * Test the creation of a simple profile model and check that specific
+ * model elements are contained in it.
+ */
+ public void testCreateSimpleProfileModel() {
final Object model = mother.createSimpleProfileModel();
Collection<Object> models = new ArrayList<Object>() { {
add(model);
@@ -92,15 +109,133 @@
}
assertNotNull("\"st\" stereotype not found in model.", st);
assertTrue(Model.getExtensionMechanismsHelper().isStereotype(st,
- ProfileMother.STEREOTYPE_NAME_ST, "Class"));
+ ProfileMother.STEREOTYPE_NAME_ST, "Class"));
}
+ /**
+ * Test saving a profile model.
+ *
+ * @throws Exception when saving the profile model fails
+ */
public void testSaveProfileModel() throws Exception {
Object model = mother.createSimpleProfileModel();
- File file = new File(testDir, "testSaveProfileModel.xmi");
+ File file = File.createTempFile("testSaveProfileModel", ".xmi");
mother.saveProfileModel(model, file);
assertTrue("The file to where the file was supposed to be saved "
- + "doesn't exist.", file.exists());
+ + "doesn't exist.", file.exists());
}
+ /**
+ * Test the creation of a profile which depends on another profile.
+ * Doesn't use the {@link ProfileMother#createXmiDependentProfile(File, ProfileMother.DependencyCreator, File, String)}
+ * method, but, it serves as good executable documentation of how this is
+ * done as a whole.
+ * @throws IOException When saving the profile models fails.
+ * @throws UmlException When something in the model subsystem goes wrong.
+ */
+ public void testXmiDependentProfile() throws IOException, UmlException {
+ Object model = mother.createSimpleProfileModel();
+ File file = File.createTempFile("simple-profile", ".xmi");
+ mother.saveProfileModel(model, file);
+ XmiReader xmiReader = Model.getXmiReader();
+ xmiReader.addSearchPath(file.getParent());
+ InputSource pIs = new InputSource(file.toURI().toURL().toExternalForm());
+ pIs.setPublicId(file.getName());
+ Collection simpleModelTopElements = xmiReader.parse(pIs, true);
+ Object model2 = mother.createSimpleProfileModel();
+ Object theClass = Model.getCoreFactory().buildClass("TheClass", model2);
+ Collection stereotypes = getFacade().getStereotypes(
+ simpleModelTopElements.iterator().next());
+ Object stereotype = stereotypes.iterator().next();
+ Model.getCoreHelper().addStereotype(theClass, stereotype);
+ File dependentProfileFile = File.createTempFile("dependent-profile",
+ ".xmi");
+ mother.saveProfileModel(model2, dependentProfileFile);
+ assertTrue("The file to where the file was supposed to be saved "
+ + "doesn't exist.", dependentProfileFile.exists());
+ assertStringInLineOfFile("The name of the file which contains the profile "
+ + "from which the dependent profile depends must occur in the "
+ + "file.",
+ file.getName(), dependentProfileFile);
+ }
+
+ /**
+ * Test the creation of a profile which depends on another profile.
+ * @throws IOException When saving the profile models fails.
+ * @throws UmlException When something in the model subsystem goes wrong.
+ */
+ public void testCreateXmiDependentProfile() throws IOException, UmlException {
+ File profilesDir = FileHelper.createTempDirectory();
+ File profileFromWhichDependsFile = File.createTempFile(
+ "simple-profile", ".xmi", profilesDir);
+ Object model = mother.createSimpleProfileModel();
+ mother.saveProfileModel(model, profileFromWhichDependsFile);
+ Model.getUmlFactory().deleteExtent(model);
+ // setting up the dependent profile creation
+ ProfileMother.DependencyCreator dependencyCreator =
+ new ProfileMother.DependencyCreator() {
+ public void create(Object profileFromWhichDepends,
+ Object dependentProfile) {
+ Object theClass = Model.getCoreFactory().buildClass("TheClass",
+ dependentProfile);
+ Collection stereotypes = getFacade().getStereotypes(
+ profileFromWhichDepends);
+ Object stereotype = stereotypes.iterator().next();
+ Model.getCoreHelper().addStereotype(theClass, stereotype);
+ }
+ };
+ String dependentProfileFilenamePrefix = "dependent-profile";
+ // actual call that executes everything
+ File dependentProfileFile = mother.createXmiDependentProfile(
+ profileFromWhichDependsFile, dependencyCreator,
+ profilesDir, dependentProfileFilenamePrefix);
+ // verifications
+ assertTrue("The file to where the file was supposed to be saved "
+ + "doesn't exist.", dependentProfileFile.exists());
+ assertStringInLineOfFile("The name of the file which contains the profile "
+ + "from which the dependent profile depends must occur in the "
+ + "file.",
+ profileFromWhichDependsFile.getName(), dependentProfileFile);
+ XmiReader xmiReader = Model.getXmiReader();
+ xmiReader.addSearchPath(profilesDir.getAbsolutePath());
+ InputSource pIs = new InputSource(
+ dependentProfileFile.toURI().toURL().toExternalForm());
+ pIs.setPublicId(dependentProfileFile.getName());
+ Collection dependentProfileModelTopElements = xmiReader.parse(pIs,
+ true);
+ assertEquals("There should exist only one top level element.",
+ 1, dependentProfileModelTopElements.size());
+ }
+
+ private void assertStringInLineOfFile(String failureMsg, String str, File file)
+ throws IOException {
+ BufferedReader fileReader = new BufferedReader(new FileReader(file));
+ try {
+ String line = "";
+ while (null != (line = fileReader.readLine())) {
+ if (line.contains(str))
+ return;
+ }
+ } finally {
+ if (fileReader != null) {
+ fileReader.close();
+ }
+ }
+ throw new AssertionFailedError(failureMsg + " '" + str
+ + "' not found in " + file.getName());
+ }
+
+ /**
+ * Test {@link ProfileMother#createProfileFilePairWithSecondDependingOnFirstThroughXmi()}.
+ * @throws IOException when file IO goes wrong...
+ * @throws UmlException when UML manipulation goes wrong...
+ */
+ public void testCreateProfilePairWithSecondDependingOnFirstThroughXmi() throws IOException, UmlException {
+ List<File> profilesFiles =
+ mother.createProfileFilePairWithSecondDependingOnFirstThroughXmi();
+ assertEquals("Should contain two elements.", 2, profilesFiles.size());
+ File baseFile = profilesFiles.get(0);
+ File dependentFile = profilesFiles.get(1);
+ assertStringInLineOfFile("", baseFile.getName(), dependentFile);
+ }
}
Modified: trunk/src/argouml-app/tests/org/argouml/profile/TestUserDefinedProfile.java
Url: http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-app/tests/org/argouml/profile/TestUserDefinedProfile.java?view=diff&pathrev=17979&r1=17978&r2=17979
==============================================================================
--- trunk/src/argouml-app/tests/org/argouml/profile/TestUserDefinedProfile.java (original)
+++ trunk/src/argouml-app/tests/org/argouml/profile/TestUserDefinedProfile.java 2010-02-10 17:24:27-0800
@@ -40,6 +40,7 @@
package org.argouml.profile;
import java.io.File;
+import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
@@ -48,6 +49,7 @@
import org.argouml.FileHelper;
import org.argouml.cognitive.Critic;
import org.argouml.model.InitializeModel;
+import org.argouml.model.Model;
import org.argouml.profile.internal.ProfileManagerImpl;
import org.argouml.profile.internal.ocl.CrOCL;
@@ -66,13 +68,22 @@
super.setUp();
InitializeModel.initializeDefault();
ProfileFacade.setManager(new ProfileManagerImpl());
-
+ // TODO: the following cleans up left overs from previous tests, but,
+ // preferably we shouldn't have to do this...
+ Collection rootElements = Model.getFacade().getRootElements();
+ for (Object rootElement : rootElements) {
+ if (Model.getFacade().isAModel(rootElement)
+ && "SimpleProfile".equals(Model.getFacade().getName(
+ rootElement))) {
+ Model.getUmlFactory().deleteExtent(rootElement);
+ }
+ }
testDir = FileHelper.setUpDir4Test(getClass());
}
@Override
protected void tearDown() throws Exception {
- FileHelper.deleteDir(testDir);
+ FileHelper.delete(testDir);
super.tearDown();
}
@@ -85,19 +96,20 @@
public void testLoadingConstructor() throws Exception {
// create profile model
ProfileMother profileMother = new ProfileMother();
- Object model = profileMother.createSimpleProfileModel();
+ final String profileName = "testLoadingConstructorProfile";
+ Object model = profileMother.createSimpleProfileModel(profileName);
// save the profile into a xmi file
File profileFile = new File(testDir, "testLoadingConstructor.xmi");
profileMother.saveProfileModel(model, profileFile);
Profile profile = new UserDefinedProfile(profileFile,
ProfileFacade.getManager());
- assertTrue(profile.getDisplayName().contains(profileFile.getName()));
+ assertEquals(profileName, profile.getDisplayName());
}
/**
- * Test the constructor used for loading a profile from a Jar file TODO Test
- * FigNode!
- *
+ * Test the constructor used for loading a profile from a Jar file.
+ * TODO: Test FigNode!
+ *
* @throws Exception if something goes wrong
*/
public void testLoadingAsFromJar() throws Exception {
Added: trunk/src/argouml-app/tests/org/argouml/profile/internal/TestDependencyResolver.java
Url: http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-app/tests/org/argouml/profile/internal/TestDependencyResolver.java?view=markup&pathrev=17979
==============================================================================
--- (empty file)
+++ trunk/src/argouml-app/tests/org/argouml/profile/internal/TestDependencyResolver.java 2010-02-10 17:24:27-0800
@@ -0,0 +1,259 @@
+/* $Id$
+ *****************************************************************************
+ * Copyright (c) 2010 Contributors - see below
+ * 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:
+ * euluis
+ *****************************************************************************
+ */
+
+package org.argouml.profile.internal;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for {@link DependencyResolver}.
+ * @author Luis Sergio Oliveira (euluis)
+ */
+public class TestDependencyResolver extends TestCase {
+ private DependencyResolver<String> resolver;
+ private DummyDependencyChecker checker;
+
+ /**
+ * @throws Exception
+ * @see junit.framework.TestCase#setUp()
+ */
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ /**
+ * Test invoke of {@link DependencyResolver#resolve()} method without any
+ * arguments.
+ */
+ public void testResolveNoArgs() {
+ DependencyChecker<String> checker2 = new DependencyChecker<String>() {
+ public boolean check(String item) {
+ return true;
+ }
+ };
+ resolver = new DependencyResolver<String>(checker2);
+ resolver.resolve();
+ }
+
+ /**
+ * Test {@link DependentString#equals(Object)}.
+ */
+ public void testDependentStringEquals() {
+ // this is neat...
+ assertEquals(new DependentString("A"), "A");
+ // but, lookout, it doesn't work both ways
+ assertFalse("A".equals(new DependentString("A")));
+ }
+
+ /**
+ * Test the resolution of several items all without any dependencies.
+ */
+ public void testResolveWithAllResolvableDependencies() {
+ final Collection<DependentString> dependentItems =
+ new ArrayList<DependentString>() { {
+ add(new DependentString("A"));
+ add(new DependentString("B"));
+ add(new DependentString("C"));
+ } };
+ checker = new DummyDependencyChecker(dependentItems);
+ resolver = new DependencyResolver<String>(checker);
+ final Collection<String> items = new ArrayList<String>() { {
+ for (DependentString dependentItem : dependentItems) {
+ add(dependentItem.theString);
+ }
+ } };
+ resolver.resolve(items);
+ assertEquals(3, checker.calls);
+ assertTrue("All the items should have been resolved.",
+ checker.resolved.containsAll(items));
+ }
+
+ /**
+ * Test the resolution of items which are all resolvable, but, handed in
+ * inverted order of their resolution:
+ * A -> {B, C}, B -> {C} and C -> {}
+ */
+ public void testResolveWithResolvableItemsButHandedInInvertedOrder() {
+ final Collection<DependentString> dependentItems =
+ new ArrayList<DependentString>() { {
+ add(new DependentString("A", new HashSet<String>() { {
+ add("B"); add("C"); } }));
+ add(new DependentString("B", new HashSet<String>() { {
+ add("C"); } }));
+ add(new DependentString("C"));
+ } };
+ checker = new DummyDependencyChecker(dependentItems);
+ resolver = new DependencyResolver<String>(checker);
+ Collection<String> items = new ArrayList<String>() { {
+ for (DependentString dependentItem : dependentItems) {
+ add(dependentItem.theString);
+ }
+ } };
+ resolver.resolve(items);
+ assertTrue("All the items should have been resolved.",
+ checker.resolved.containsAll(items));
+ }
+
+ /**
+ * Test the resolution of items which are all resolvable, but, handed first
+ * partially and not resolvable, then a new call to resolve delivers the
+ * solution.
+ * First call: A -> {B, C}, B -> {C} and C -> {D}
+ * Second call: D -> {}
+ */
+ public void testResolveWithResolvableItemsButInTwoCalls() {
+ final Collection<DependentString> dependentItems =
+ new ArrayList<DependentString>() { {
+ add(new DependentString("C", new HashSet<String>() { {
+ add("D"); } }));
+ add(new DependentString("D"));
+ } };
+ checker = new DummyDependencyChecker(dependentItems);
+ resolver = new DependencyResolver<String>(checker);
+ Collection<String> items1 = new ArrayList<String>() { { add("C"); } };
+ resolver.resolve(items1);
+ assertEquals("No item should have been resolved.", 0,
+ checker.resolved.size());
+ Collection<String> items2 = new ArrayList<String>() { { add("D"); } };
+ resolver.resolve(items2);
+ assertTrue("All the items should have been resolved.",
+ checker.resolved.containsAll(items1)
+ && checker.resolved.containsAll(items2));
+ }
+
+ /**
+ * Test the resolution of items which are not resolvable at first, but,
+ * which after injecting the dependency, will afterwards be resolved with
+ * the non-arguments resolve being invoked.
+ * <ol>
+ * <li>resolve(X -> {Z, Y}, Z -> {Y}) → nothing resolved</li>
+ * <li>{@link DependencyResolver#resolve()} call → nothing
+ * resolved</li>
+ * <li>inject Y as resolved</li>
+ * <li>{@link DependencyResolver#resolve()} call → X and Z
+ * resolved</li>
+ * </ol>
+ */
+ public void testResolveWithSolutionInjectedByThirdParty() {
+ final Collection<DependentString> dependentItems =
+ new ArrayList<DependentString>() { {
+ add(new DependentString("X", new HashSet<String>() { {
+ add("Z"); add("Y"); } }));
+ add(new DependentString("Z", new HashSet<String>() { {
+ add("Y"); } }));
+ } };
+ checker = new DummyDependencyChecker(dependentItems);
+ resolver = new DependencyResolver<String>(checker);
+ Collection<String> items = new ArrayList<String>() { {
+ add("X"); add("Z"); } };
+ resolver.resolve(items);
+ assertEquals("No item should have been resolved.", 0,
+ checker.resolved.size());
+ resolver.resolve();
+ assertEquals("No item should have been resolved.", 0,
+ checker.resolved.size());
+ checker.resolved.add("Y");
+ resolver.resolve();
+ assertTrue("All the items should have been resolved.",
+ checker.resolved.containsAll(items));
+ }
+}
+
+class DependentString {
+ String theString;
+ Set<String> dependencies;
+
+ DependentString(String s, Set<String> dependencies) {
+ theString = s;
+ this.dependencies = dependencies;
+ if (dependencies == null) {
+ this.dependencies = new HashSet<String>();
+ }
+ }
+
+ DependentString(String s) {
+ this(s, new HashSet<String>());
+ }
+
+ /**
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ return theString.equals(obj);
+ }
+
+ /**
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return theString.hashCode();
+ }
+
+ /**
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ for (String dependency : dependencies) {
+ sb.append(dependency);
+ sb.append(", ");
+ }
+ return theString + " -> {" + sb.toString() + "}";
+ }
+}
+
+class DummyDependencyChecker implements DependencyChecker<String> {
+ Collection<String> items;
+ Collection<DependentString> dependentItems;
+ Collection<String> resolved = new HashSet<String>();
+ int calls = 0;
+
+ DummyDependencyChecker(final Collection<DependentString> items) {
+ this.items = new ArrayList<String>() { {
+ for (DependentString item : items) {
+ add(item.theString);
+ }
+ } };
+ this.dependentItems = items;
+ }
+
+ /**
+ * @see org.argouml.profile.internal.DependencyChecker#check(java.lang.Object)
+ */
+ public boolean check(String item) {
+ calls++;
+ if (items.contains(item)) {
+ DependentString item2Check = null;
+ for (DependentString theItem : dependentItems) {
+ if (theItem.equals(item)) {
+ item2Check = theItem;
+ break;
+ }
+ }
+ if (resolved.containsAll(item2Check.dependencies)) {
+ resolved.add(item2Check.theString);
+ return true;
+ }
+ }
+ return false;
+ }
+}
Modified: trunk/src/argouml-app/tests/org/argouml/profile/internal/TestProfileManagerImpl.java
Url: http://argouml.tigris.org/source/browse/argouml/trunk/src/argouml-app/tests/org/argouml/profile/internal/TestProfileManagerImpl.java?view=diff&pathrev=17979&r1=17978&r2=17979
==============================================================================
--- trunk/src/argouml-app/tests/org/argouml/profile/internal/TestProfileManagerImpl.java (original)
+++ trunk/src/argouml-app/tests/org/argouml/profile/internal/TestProfileManagerImpl.java 2010-02-10 17:24:27-0800
@@ -1,6 +1,6 @@
/* $Id$
*****************************************************************************
- * Copyright (c) 2009 Contributors - see below
+ * Copyright (c) 2009-2010 Contributors - see below
* 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
@@ -8,6 +8,7 @@
*
* Contributors:
* thn
+ * euluis
*****************************************************************************
*
* Some portions of this file was previously release using the BSD License:
@@ -38,7 +39,15 @@
package org.argouml.profile.internal;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -46,15 +55,18 @@
import junit.framework.TestCase;
+import org.argouml.FileHelper;
import org.argouml.model.InitializeModel;
+import org.argouml.model.UmlException;
import org.argouml.profile.Profile;
import org.argouml.profile.ProfileException;
import org.argouml.profile.ProfileManager;
+import org.argouml.profile.ProfileMother;
import org.argouml.uml.cognitive.critics.ProfileGoodPractices;
/**
* Tests for the ProfileManagerImpl class.
- *
+ *
* @author Luis Sergio Oliveira (euluis)
*/
public class TestProfileManagerImpl extends TestCase {
@@ -137,5 +149,111 @@
assertFalse(manager.getRegisteredProfiles().contains(testProfile));
assertFalse(manager.getDefaultProfiles().contains(testProfile));
}
+
+ /**
+ * When loading profiles, check that XMI profile dependency resolution is
+ * handled correctly when two user defined profiles are handed to
+ * {@link ProfileManagerImpl#loadProfiles(List)} with the first being the
+ * dependent profile of the second.
+ *
+ * @throws IOException when file IO goes wrong...
+ * @throws UmlException when UML manipulation goes wrong...
+ */
+ public void testXmiProfileDependencyResolutionWithProfilesHandedInReverseOrderOfDependencyInOneCall()
+ throws IOException, UmlException {
+ List<Profile> registeredProfiles = manager.getRegisteredProfiles();
+ int numRegisteredBefore = registeredProfiles.size();
+ ProfileMother mother = new ProfileMother();
+ List<File> profileFiles =
+ mother.createProfileFilePairWithSecondDependingOnFirstThroughXmi();
+ Collections.reverse(profileFiles);
+
+ ProfileManagerImpl managerImpl = (ProfileManagerImpl) manager;
+ managerImpl.loadProfiles(profileFiles);
+
+ List<Profile> registeredProfilesAfter =
+ manager.getRegisteredProfiles();
+ assertEquals("Now we should have two more registered profiles.",
+ numRegisteredBefore + 2, registeredProfilesAfter.size());
+ }
+
+ /**
+ * When loading profiles, check that XMI profile dependency resolution is
+ * handled correctly when two user defined profiles are handed to
+ * {@link ProfileManagerImpl#loadProfiles(List)} in two calls, with the
+ * first call handing the dependent profile of the second and only on the
+ * second call being handed the profile from which the first depends.
+ *
+ * @throws IOException when file IO goes wrong...
+ * @throws UmlException when UML manipulation goes wrong...
+ */
+ public void testXmiProfileDependencyResolutionWithProfilesHandedInReverseOrderOfDependencyInTwoCalls()
+ throws IOException, UmlException {
+ List<Profile> registeredProfiles = manager.getRegisteredProfiles();
+ int numRegisteredBefore = registeredProfiles.size();
+ ProfileMother mother = new ProfileMother();
+ List<File> profileFiles =
+ mother.createProfileFilePairWithSecondDependingOnFirstThroughXmi();
+
+ File baseProfileFile = profileFiles.get(0);
+ String baseProfileFileName = baseProfileFile.getName();
+ File baseProfileDirectory = FileHelper.createTempDirectory(
+ getClass().getCanonicalName());
+ String newBaseProfileFileName = "new-base-profile.xmi";
+ File newBaseProfileFile = new File(baseProfileDirectory,
+ newBaseProfileFileName);
+ assertTrue(baseProfileFile.renameTo(newBaseProfileFile));
+ baseProfileFile = newBaseProfileFile;
+
+ ProfileManagerImpl managerImpl = (ProfileManagerImpl) manager;
+
+ File dependentProfileFile = profileFiles.get(1);
+ replaceStringInFile(dependentProfileFile, baseProfileFileName,
+ newBaseProfileFileName);
+ ArrayList<File> dependentProfileList = new ArrayList<File>();
+ dependentProfileList.add(dependentProfileFile);
+ managerImpl.loadProfiles(dependentProfileList);
+ assertEquals("We should have exaclty the same number of registered "
+ + "profiles as in the begining.",
+ numRegisteredBefore, manager.getRegisteredProfiles().size());
+
+ ArrayList<File> baseProfileList = new ArrayList<File>();
+ baseProfileList.add(baseProfileFile);
+ managerImpl.loadProfiles(baseProfileList);
+
+ assertEquals("Now we should have two more registered profiles.",
+ numRegisteredBefore + 2, manager.getRegisteredProfiles().size());
+ }
+ private void replaceStringInFile(File file, String regex,
+ String replacement) throws IOException {
+ StringBuffer fileContents = new StringBuffer();
+ BufferedReader reader = null;
+ String fileContents2 = null;
+ try {
+ reader = new BufferedReader(new FileReader(file));
+ String line = "";
+ while (null != (line = reader.readLine())) {
+ fileContents.append(line);
+ fileContents.append("\n");
+ }
+ fileContents2 = fileContents.toString();
+ fileContents2 = fileContents2.replaceAll(regex, replacement);
+ } finally {
+ if (reader != null) {
+ reader.close();
+ }
+ }
+ if (fileContents2 != null && file.delete() && file.createNewFile()) {
+ BufferedWriter writer = null;
+ try {
+ writer = new BufferedWriter(new FileWriter(file));
+ writer.append(fileContents2);
+ } finally {
+ if (writer != null) {
+ writer.close();
+ }
+ }
+ }
+ }
}
------------------------------------------------------
http://argouml.tigris.org/ds/viewMessage.do?dsForumId=5905&dsMessageId=2446587
To unsubscribe from this discussion, e-mail: [[email protected]].