Package org.openiaml.model.tests.release

Source Code of org.openiaml.model.tests.release.GmfGenTestCase$IntegerHolder

/**
*
*/
package org.openiaml.model.tests.release;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.transform.TransformerException;
import javax.xml.xpath.XPathExpressionException;

import junit.framework.AssertionFailedError;

import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EPackage;
import org.openiaml.emf.SoftCache;
import org.openiaml.model.model.ModelPackage;
import org.openiaml.model.model.domain.DomainPackage;
import org.openiaml.model.model.users.UsersPackage;
import org.openiaml.model.tests.XmlTestCase;
import org.openiaml.model.tests.model.ModelTestCase;
import org.openiaml.model.xpath.IterableElementList;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

/**
* Tests all .gmfgens
*
* @author jmwright
*
*/
public class GmfGenTestCase extends XmlTestCase {
 
  /**
   * A soft in-memory cache of gmfgen filenames to
   * loaded XML documents.
   */
  private static SoftCache<String,Document> gmfgenCache = new SoftCache<String,Document>() {

    @Override
    public Document retrieve(String input) {
      try {
        return loadDocument(input);
      } catch (Exception e) {
        throw new RuntimeException(e.getMessage(), e);
      }
    }

  };
 
  public static SoftCache<String,Document> getCache() {
    return gmfgenCache;
  }
   
  /**
   * Create a list of gmfmaps from {@link PluginsTestCase}.
   *
   * @return
   */
  private static Set<String> getGenList() {
    return PluginsTestCase.getAllGmfGens();
  }
 
  public void testGenListIsntEmpty() {
    assertNotSame(0, getGenList().size());
  }

  /**
   * Every node should have no more than one OpenDiagram policy.
   *
   * @throws Exception
   */
  public void testOnlyOneOpenDiagramPolicy() throws Exception {
    for (String filename : getGenList()) {
      Document doc = getCache().get(filename);
     
      IterableElementList nodes = xpath(doc, "/GenEditorGenerator/diagram/topLevelNodes");
      assertFalse(filename + ": No nodes found", nodes.isEmpty());
     
      for (Element node : nodes) {
        // directly contained OpenDiagramPolicies
        IterableElementList opens = xpath(node, "behaviour");
        boolean foundOpen = false;
        for (Element open : opens) {
          if (open.getAttribute("xsi:type").equals("gmfgen:OpenDiagramBehaviour")) {
            assertFalse(filename + ": More than one OpenDiagram policy found for node '" + node + "'", foundOpen);
            foundOpen = true;
          }
        }
      }

      IterableElementList links = xpath(doc, "/GenEditorGenerator/diagram/links");
      assertFalse(filename + ": No links found", links.isEmpty());
      for (Element link : links) {
        // directly contained OpenDiagramPolicies
        IterableElementList opens = xpath(link, "behaviour");
        boolean foundOpen = false;
        for (Element open : opens) {
          if (open.getAttribute("xsi:type").equals("gmfgen:OpenDiagramBehaviour")) {
            assertFalse(filename + ": More than one OpenDiagram policy found for link '" + link + "'", foundOpen);
            foundOpen = true;
          }
        }
      }
    }
  }

  /**
   * All read-only labels inside nodes with OpenDiagramPolicies should
   * also have an OpenDiagramPolicy.
   *
   * @throws Exception
   */
  public void testReadOnlyOpenDiagramPolicies() throws Exception {
    for (String filename : getGenList()) {
      Document doc = getCache().get(filename);
     
      // will do both links and nodes
      IterableElementList labels = xpath(doc, "//labels[@readOnly='true']");
      assertFalse(filename + ": No read-only labels found", labels.isEmpty());
     
      for (Element label : labels) {
        String labelName = label.getAttribute("editPartClassName");
       
        // does the parent have an OpenDiagramPolicy?
        Element parent = (Element) label.getParentNode();
        Element pOpen = hasXpathFirst(parent, "behaviour");
        if (pOpen != null && pOpen.getAttribute("xsi:type").equals("gmfgen:OpenDiagramBehaviour")) {
          // yes! this label should also have an open diagram policy
          Element open = hasXpathFirst(label, "behaviour");
          assertNotNull(filename + ": Read-only label '" + labelName + "' must have an OpenDiagram behaviour, like its parent", open);
         
          // make sure it's a behaviour
          assertEquals(filename + ": Read-only label '" + labelName + "' has an incorrect OpenDiagram behaviour",
              open.getAttribute("xsi:type"), "gmfgen:OpenDiagramBehaviour");
        }
      }

    }
  }
 
  /**
   * Non read-only labels inside nodes cannot contain OpenDiagramPolicies.
   * (Otherwise they could not be edited by double clicking.)
   *
   * @throws Exception
   */
  public void testNonReadOnlyCannotHaveOpenPolicies() throws Exception {
    for (String filename : getGenList()) {
      Document doc = getCache().get(filename);
     
      // will do both links and nodes
      IterableElementList labels = xpath(doc, "//labels[not(@readOnly='true')]");
      assertFalse(filename + ": No normal labels found", labels.isEmpty());
     
      for (Element label : labels) {
        String labelName = label.getAttribute("editPartClassName");
       
        // it cannot have a OpenDiagram behaviour
        IterableElementList bh = xpath(label, "behaviour");
        for (Element b : bh) {
          assertNotEqual(filename + ": Normal editable label '" + labelName + "' cannot have an OpenDiagram behaviour",
            b.getAttribute("xsi:type"), "gmfgen:OpenDiagramBehaviour");
        }
      }

    }
  }
 
  /**
   * All labels with OpenDigramPolicies must match those of
   * their parents.
   *
   * @throws Exception
   */
  public void testLabelOpenDiagramsMatch() throws Exception {
    for (String filename : getGenList()) {
      Document doc = getCache().get(filename);
     
      // will do both links and nodes
      IterableElementList labels = xpath(doc, "//labels");
      assertFalse(filename + ": No labels found", labels.isEmpty());
     
      for (Element label : labels) {
        String labelName = label.getAttribute("editPartClassName");
       
        // iterate over behaviours
        IterableElementList beh = xpath(label, "behaviour");
        for (Element b : beh) {
          if (b.getAttribute("xsi:type").equals("gmfgen:OpenDiagramBehaviour")) {
            // the parent must have the same node
           
            String query = "../behaviour[@editPolicyClassName='" + b.getAttribute("editPolicyClassName") + "' and @diagramKind='" + b.getAttribute("diagramKind") + "' and @editorID='" + b.getAttribute("editorID") + "']";
            Element parentOpen = hasXpathFirst(label, query);
            assertNotNull(filename + ": Could not find matching parent OpenDiagram for label '" + labelName + "' matching '" + query + "'", parentOpen);
          }
        }
      }
    }
  }
 
  /**
   * For an OpenDiagramPolicy, the destination editor must be a
   * class that can contain the element referred to in the OpenDiagramPolicy.
   *
   * @throws Exception
   */
  public void testOpenDiagramTargetElement() throws Exception {
    for (String filename : getGenList()) {
      Document doc = getCache().get(filename);
     
      IterableElementList nodes = xpath(doc, "/GenEditorGenerator/diagram/topLevelNodes");
      nodes.addAll(xpath(doc, "/GenEditorGenerator/diagram/links"));
      assertFalse(filename + ": No nodes found", nodes.isEmpty());
     
      for (Element node : nodes) {
        // find the meta element for this node
        Element meta = xpathFirst(node, "modelFacet/metaClass");
        // iaml.genmodel#//model/CompositeOperation
        String metaHref = meta.getAttribute("href");
       
        IterableElementList beh = xpath(node, "behaviour");
        for (Element b : beh) {
          if (b.getAttribute("xsi:type").equals("gmfgen:OpenDiagramBehaviour")) {
            // an OpenDiagram policy
            assertOpenDiagramElementMatches(filename, b.getAttribute("diagramKind"), metaHref);
          }
        }
      }
    }
  }

  /**
   * Assert that the given model ID can store the element
   * referred to in metaHref.
   *
   * @param filename
   * @param modelID "Iaml_Operation"
   * @param metaHref "iaml.genmodel#//model/CompositeOperation"
   */
  private void assertOpenDiagramElementMatches(String filename,
      String modelID, String metaHref) throws Exception {

    // first, lets get the EClass of the meta element
    String metaElementName = metaHref.substring(metaHref.lastIndexOf("/") + 1);
    // resolve
    EClass meta = resolveSimpleEClass(metaElementName);
   
    // and now lets find the EClass of the editor
    EClass editor = getEditorEClass(filename, modelID);
   
    assertNotNull(meta);
    assertNotNull(editor);
   
    // the meta element should be a subclass of the editor
    assertTrue(filename + ": Element '" + metaHref + "' is not a subclass of diagram type '" + modelID + "' [resolved meta = '" + meta + "', editor = '" + editor + "']",
        editor.isSuperTypeOf(meta));
  }

  private Map<String, EClass> foundClasses = new HashMap<String, EClass>();
 
  /**
   * Get the root EClass of the given modelID. Iterates over
   * existing .gmfgens.
   *
   * @param modelID
   * @return
   */
  private EClass getEditorEClass(String filename2, String modelID) throws Exception {
    if (foundClasses.containsKey(modelID))
      return foundClasses.get(modelID);
   
    for (String filename : getGenList()) {
      Document doc = getCache().get(filename);
      Element root = xpathFirst(doc, "/GenEditorGenerator");
      if (root.getAttribute("modelID").equals(modelID)) {
        Element domainDiagramElement = xpathFirst(doc, "/GenEditorGenerator/diagram/domainDiagramElement");
       
        String href = domainDiagramElement.getAttribute("href");
        // trim to last /
        href = href.substring(href.lastIndexOf("/") + 1);
       
        EClass result = resolveSimpleEClass(href);
        foundClasses.put(modelID, result);
        return result;
      }     
    }
   
    fail(filename2 + ": Could not find Editor EClass for model ID '" + modelID + "'");
    return null;
  }
 
  private static Map<String, EClass> resolvedClasses = new HashMap<String, EClass>();

  /**
   * Resolve a simple meta element. This assumes that the same
   * element name does not occur more than once in the given
   * metamodel.
   *
   * Uses the factory map found in {@link org.openiaml.model.tests.model.ModelTestCase}.
   *
   * @param metaElementName "SingleOperation"
   * @return
   */
  public static EClass resolveSimpleEClass(String metaElementName) {
    if (resolvedClasses.containsKey(metaElementName)) {
      return resolvedClasses.get(metaElementName);
    }
   
    for (EPackage pkg : ModelTestCase.getFactoryMap().keySet()) {
      EClassifier cf = pkg.getEClassifier(metaElementName);
      if (cf != null && cf instanceof EClass) {
        // found it!
        EClass result = (EClass) cf;
        resolvedClasses.put(metaElementName, result);
        return result;
      }
    }
    fail("Could not resolve simple EClass name '" + metaElementName + "'");
    return null;
  }
 
  public interface XmlDocumentIterator {
   
    /**
     * Execute something over the given XML document, which
     * has the given filename.
     *
     * @param filename
     * @param doc
     */
    public void execute(String filename, Document doc) throws Exception;
   
  }
 
  public abstract class DefaultIterator implements XmlDocumentIterator {

    /**
     * Log a message; this will include a helpful link to
     * the current file.
     *
     * @param message
     */
    public void log(String message) {
      System.out.println(simplifyFilename(filename) + ": " + message);
    }
   
    private String simplifyFilename(String s) {
      return s.substring(s.lastIndexOf(File.separator) + 1);
    }

    private String filename;
   
    @Override
    public void execute(String filename, Document doc) throws Exception {
      this.filename = filename;
      execute2(filename, doc);
    }
   
    public void saveDocument(Document doc, String filename) throws IOException, TransformerException {
      log("Saving to disk");
      GmfGenTestCase.saveDocument(doc, filename);
    }
   
    /**
     * Does the actual work.
     */
    public abstract void execute2(String filename, Document doc) throws Exception;
   
  }
 
  /**
   * Iterate over all the .gmfgen's with the given iterator.
   * If an error occurs while iterating, catches the error and
   * appends the filename.
   *
   * @param it
   * @throws Exception
   */
  protected void iterate(XmlDocumentIterator it) throws Exception {
    for (String filename : getGenList()) {
      try {
        Document doc = getCache().get(filename);
       
        it.execute(filename, doc);
      } catch (Throwable e) {
        throw new RuntimeException(filename + ": " + e.getMessage(), e);
      }
    }
  }
 
  public abstract class AttributeIterator extends DefaultIterator {

    /**
     * The attribute to check on /GenEditorGenerator, e.g. "modelID"
     * @return
     */
    public abstract String getAttributeName();
   
    /**
     * Get the expected value for the given filename.
     *
     * @param filename
     * @param current the current value
     */
    public abstract String getExpected(String filename, String current);
   
    public String getXpathSelector() {
      return "/GenEditorGenerator";
    }
   
    @Override
    public void execute2(String filename, Document doc) throws Exception {
      IterableElementList roots = xpath(doc, getXpathSelector());
      for (Element root : roots) {
        String current = root.getAttribute(getAttributeName());
       
        String expected = getExpected(filename, current);
        if (isEmpty(current)) {
          log("Setting " + getAttributeName() + " to " + expected);
          root.setAttribute(getAttributeName(), expected);
          saveDocument(doc, filename);
        } else {
          if (!expected.equals(current)) {
            if (forceSet()) {
              log("Force setting " + getAttributeName() + " to " + expected);
              root.setAttribute(getAttributeName(), expected);
              saveDocument(doc, filename);
            } else {
              assertEquals(expected, current);
            }
          }
        }
      }
    }
   
    /**
     * Should we forceably set the attribute if it is incorrect?
     * @return
     */
    public boolean forceSet() {
      return false;
    }
   
  }
 
  /**
   * Every .gmfgen should have a ModelID.
   * Sets the ModelID to the filename if not.
   */
  public void testModelID() throws Exception {
    iterate(new AttributeIterator() {

      @Override
      public String getAttributeName() {
        return "modelID";
      }

      @Override
      public String getExpected(String filename, String current) {
        filename = getName(filename);
        if (filename.equals("root")) {
          return "Iaml";
        }
        return "Iaml_" + camelCase(filename);
      }
     
    });
   
  }

  public void testPackageNamePrefix() throws Exception {
    iterate(new AttributeIterator() {
     
      @Override
      public String getAttributeName() {
        return "packageNamePrefix";
      }

      @Override
      public String getExpected(String filename, String current) {
        return getPluginName(filename);
      }
     
    });
   
  }
 
  public void testDiagramFileExtension() throws Exception {
    iterate(new AttributeIterator() {

      @Override
      public String getAttributeName() {
        return "diagramFileExtension";
      }

      @Override
      public String getExpected(String filename, String current) {
        if (getName(filename).equals("root")) {
          return "iaml_diagram";
        }
        return "iaml_" + getName(filename) + "_diagram";
      }
     
    });
   
  }
 
  public void testDomainFileExtension() throws Exception {
    iterate(new AttributeIterator() {

      @Override
      public String getAttributeName() {
        return "domainFileExtension";
      }

      @Override
      public String getExpected(String filename, String current) {
        if (getName(filename).equals("root")) {
          return "iaml";
        }
        return "iaml_" + getName(filename);
      }
     
    });
   
  }
 
  public void testDynamicTemplates() throws Exception {
    iterate(new AttributeIterator() {

      @Override
      public String getAttributeName() {
        return "dynamicTemplates";
      }

      @Override
      public String getExpected(String filename, String current) {
        return "true";
      }
     
    });
   
  }
 
  public void testTemplateDirectory() throws Exception {
    iterate(new AttributeIterator() {

      @Override
      public String getAttributeName() {
        return "templateDirectory";
      }

      @Override
      public String getExpected(String filename, String current) {
        return "/org.openiaml.model/templates/";
      }
     
    });
   
  }
 
  public void testValidationEnabled() throws Exception {
    iterate(new AttributeIterator() {

      @Override
      public String getAttributeName() {
        return "validationEnabled";
      }

      @Override
      public String getExpected(String filename, String current) {
        return "true";
      }

      @Override
      public String getXpathSelector() {
        return "/GenEditorGenerator/diagram";
      }
     
    });
   
  }
 
  public void testValidationDecorators() throws Exception {
    iterate(new AttributeIterator() {

      @Override
      public String getAttributeName() {
        return "validationDecorators";
      }

      @Override
      public String getExpected(String filename, String current) {
        return "true";
      }

      @Override
      public String getXpathSelector() {
        return "/GenEditorGenerator/diagram";
      }
     
    });
   
  }
 
  public List<String> ALL_PLUGIN_NAMES = getAllPluginNames();
 
  public List<String> getAllPluginNames() {
    try {
      List<String> result = new ArrayList<String>();
      for (String filename : getGenList()) {
        result.add(getName(filename));
      }
      return result;
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
 
  /**
   * Converts "root", "foo" into "iaml", "iaml_foo".
   *
   * @return
   */
  public List<String> getAllShortcuts() {
    List<String> result = new ArrayList<String>();
    for (String name : ALL_PLUGIN_NAMES) {
      if (name.equals("root")) {
        result.add("iaml");
      } else {
        result.add("iaml_" + name);
      }
    }
    return result;
  }
 
  public void testContainsShortcutsTo() throws Exception {
    iterate(new DefaultIterator() {

      @Override
      public void execute2(String filename, Document doc)
          throws Exception {
       
        Element diagram = xpathFirst(doc, "/GenEditorGenerator/diagram");
        boolean changed = false;
        for (String shortcut : getAllShortcuts()) {
          if (hasXpathFirst(diagram, "containsShortcutsTo[text()='" + shortcut + "']") == null) {
            // add it
            log("Adding containsShortcutsTo: " + shortcut);
           
            Element e = doc.createElement("containsShortcutsTo");
            e.setTextContent(shortcut);
            diagram.appendChild(e);
            changed = true;
          }
        }
       
        if (changed) {
          saveDocument(doc, filename);
        }
       
      }
     
    });
  }
 
  public void testShortcutsProvidedFor() throws Exception {
    iterate(new DefaultIterator() {

      @Override
      public void execute2(String filename, Document doc)
          throws Exception {
       
        Element diagram = xpathFirst(doc, "/GenEditorGenerator/diagram");
        boolean changed = false;
        for (String shortcut : getAllShortcuts()) {
          if (hasXpathFirst(diagram, "shortcutsProvidedFor[text()='" + shortcut + "']") == null) {
            // add it
            log("Adding shortcutsProvidedFor: " + shortcut);
           
            Element e = doc.createElement("shortcutsProvidedFor");
            e.setTextContent(shortcut);
            diagram.appendChild(e);
            changed = true;
          }
        }
       
        if (changed) {
          saveDocument(doc, filename);
        }
       
      }
     
    });
  }
 
  public void testPluginId() throws Exception {
    iterate(new AttributeIterator() {

      @Override
      public String getAttributeName() {
        return "iD";
      }

      @Override
      public String getExpected(String filename, String current) {
        filename = getName(filename);
        if (filename.equals("root")) {
          return "org.openiaml.model.diagram";
        } else {
          return "org.openiaml.model.diagram." + filename;
        }
      }

      @Override
      public String getXpathSelector() {
        return "/GenEditorGenerator/plugin";
      }
     
    });
   
  }
 
  public void testPluginName() throws Exception {
    iterate(new AttributeIterator() {

      @Override
      public String getAttributeName() {
        return "name";
      }

      @Override
      public String getExpected(String filename, String current) {
        filename = getName(filename);
        if (filename.equals("root")) {
          return "Iaml Diagram Plugin";
        } else {
          return "Iaml Diagram Plugin (" + spaceCase(filename) + ")";
        }
      }

      @Override
      public String getXpathSelector() {
        return "/GenEditorGenerator/plugin";
      }
     
    });
   
  }
 
  public void testPluginProvider() throws Exception {
    iterate(new AttributeIterator() {

      @Override
      public String getAttributeName() {
        return "provider";
      }

      @Override
      public String getExpected(String filename, String current) {
        try {
          return PluginsTestCase.getVendor();
        } catch (Throwable e) {
          throw new RuntimeException(e.getMessage(), e);
        }
      }

      @Override
      public String getXpathSelector() {
        return "/GenEditorGenerator/plugin";
      }
     
    });
   
  }

  public void testPluginVersion() throws Exception {
    iterate(new AttributeIterator() {

      @Override
      public String getAttributeName() {
        return "version";
      }

      @Override
      public String getExpected(String filename, String current) {
        try {
          return PluginsTestCase.getVersion();
        } catch (Exception e) {
          throw new RuntimeException(e.getMessage(), e);
        }
      }

      @Override
      public String getXpathSelector() {
        return "/GenEditorGenerator/plugin";
      }

      @Override
      public boolean forceSet() {
        return true;
      }
     
    });
   
  }
 
  /**
   * all preferencePages should have an ID
   * of 'org.openiaml.model.diagram.xxx'.
   *
   * @throws Exception
   */
  public void testPreferencePages() throws Exception {
    iterate(new AttributeIterator() {

      @Override
      public String getAttributeName() {
        return "iD";
      }

      @Override
      public String getExpected(String filename, String current) {
        return current.replace("org.openiaml.diagram", "org.openiaml.model.diagram");
      }

      @Override
      public String getXpathSelector() {
        return "/GenEditorGenerator/diagram/preferencePages";
      }

      @Override
      public boolean forceSet() {
        return true;
      }
     
    });
   
  }
 
 
  /**
   * all preferencePages children should have an ID
   * of 'org.openiaml.model.diagram.xxx'.
   *
   * @throws Exception
   */
  public void testPreferencePagesChildren() throws Exception {
    iterate(new AttributeIterator() {

      @Override
      public String getAttributeName() {
        return "iD";
      }

      @Override
      public String getExpected(String filename, String current) {
        return current.replace("org.openiaml.diagram", "org.openiaml.model.diagram");
      }

      @Override
      public String getXpathSelector() {
        return "/GenEditorGenerator/diagram/preferencePages/children";
      }

      @Override
      public boolean forceSet() {
        return true;
      }
     
    });
   
  }
 
  public String getName(String filename) {
    assertTrue(filename, filename.endsWith(".gmfgen"));
    filename = filename.substring(filename.lastIndexOf("/") + 1);
    filename = filename.substring(filename.lastIndexOf("\\") + 1);
    filename = filename.substring(0, filename.indexOf(".gmfgen"));
    return filename;
  }
 
  /**
   * Tests {@link #getName(filename)}.
   */
  public void testGetName() {
    assertEquals("root", getName("../root.gmfgen"));
    assertEquals("root", getName("root.gmfgen"));
    assertEquals("another", getName("../another/directory//another.gmfgen"));
    assertEquals("root", getName("..\\another\\directory\\root.gmfgen"));
  }

  private String getPluginName(String filename) {
    filename = getName(filename);
    if (filename.equals("root")) {
      return "org.openiaml.model.diagram";
    } else {
      return "org.openiaml.model.diagram." + filename;
    }
  }
 
  /**
   * Tests {@link #getPluginName(filename)}.
   */
  public void testGetPluginName() {
    assertEquals("org.openiaml.model.diagram", getPluginName("../root.gmfgen"));
    assertEquals("org.openiaml.model.diagram", getPluginName("root.gmfgen"));
    assertEquals("org.openiaml.model.diagram.another", getPluginName("../another/directory//another.gmfgen"));
    assertEquals("org.openiaml.model.diagram.test_test_test", getPluginName("..\\another\\directory\\test_test_test.gmfgen"));
  }

 
  /**
   * Is the given string null or empty?
   *
   * @param modelID
   * @return
   */
  private boolean isEmpty(String modelID) {
    return modelID == null || "".equals(modelID);
  }

  /**
   * Converts "foo_bar" to "FooBar".
   *
   * @param underCase
   * @return
   */
  private String camelCase(String underCase) {
    String[] s = underCase.split("_");
    String r = "";
    for (String s2 : s) {
      r += Character.toUpperCase(s2.charAt(0)) + s2.substring(1).toLowerCase();
    }
    return r;
  }
 
  /**
   * Tests {@link #camelCase(String)}.
   */
  public void testCamelCase() {
    assertEquals("FooBar", camelCase("foo_bar"));
    assertEquals("Foo", camelCase("foo"));
  }

  /**
   * Converts "foo_bar" to "Foo Bar".
   *
   * @param underCase
   * @return
   */
  private String spaceCase(String underCase) {
    String[] s = underCase.split("_");
    String r = "";
    for (String s2 : s) {
      if (!r.equals(""))
        r += " ";
      r += Character.toUpperCase(s2.charAt(0)) + s2.substring(1).toLowerCase();
    }
    return r;
  }
 
  /**
   * Tests {@link #spaceCase(String)}.
   */
  public void testSpaceCase() {
    assertEquals("Foo Bar", spaceCase("foo_bar"));
    assertEquals("Foo", spaceCase("foo"));
  }

  /**
   * Represents a triple of (diagram canvas element, diagram ID, diagram gmfgen filename).
   *
   * @author jmwright
   *
   */
  public class RootElementPair {
    private EClass element;
    private String modelID;
    private String filename;
   
    /**
     * @param element
     * @param modelID
     */
    public RootElementPair(EClass element, String modelID, String filename) {
      super();
      this.element = element;
      this.modelID = modelID;
      this.filename = filename;
    }
   
    public EClass getElement() {
      return element;
    }
    public String getModelID() {
      return modelID;
    }
    public String getFilename() {
      return filename;
    }
 
  }
 
  /**
   * Fix any missing OpenBehaviours, and check existing
   * behaviours.
   *
   * @throws Exception
   */
  public void testFixOpenBehaviours() throws Exception {
    // initialise all root elements
    final List<RootElementPair> rootElements = new ArrayList<RootElementPair>();
   
    // from all gmfgens
    iterate(new DefaultIterator() {
     
      @Override
      public void execute2(String filename, Document doc) throws Exception {
        // find the
        Element root = xpathFirst(doc, "/GenEditorGenerator");
        String modelID = root.getAttribute("modelID");
        if (getName(filename).equals("root"))
          modelID = "Iaml";
        assertFalse("Document modelID has not been set yet", isEmpty(modelID));
        Element domainDiagramElement = xpathFirst(doc, "/GenEditorGenerator/diagram/domainDiagramElement");
       
        String href = domainDiagramElement.getAttribute("href");
        // trim to last /
        href = href.substring(href.lastIndexOf("/") + 1);
         
        EClass rootElement = resolveSimpleEClass(href);

        rootElements.add(new RootElementPair(rootElement, modelID, filename));
      }
    });
   
    // and then check all gmfgens that these root elements are coorect
    iterate(new DefaultIterator() {
     
      @Override
      public void execute2(String filename, Document doc) throws Exception {
        // will do both links and nodes
        IterableElementList nodes = xpath(doc, "/GenEditorGenerator/diagram/topLevelNodes");
        nodes.addAll(xpath(doc, "/GenEditorGenerator/diagram/links"));
        assertFalse(filename + ": No nodes found", nodes.isEmpty());
       
        boolean changed = false;
        for (Element node : nodes) {
          // find the meta element for this node
          Element meta = xpathFirst(node, "modelFacet/metaClass");
          // iaml.genmodel#//model/CompositeOperation
          String metaHref = meta.getAttribute("href");
          // CompositeOperation
          metaHref = metaHref.substring(metaHref.lastIndexOf("/") + 1);
         
          EClass metaElement = resolveSimpleEClass(metaHref);
         
          try {
            RootElementPair pair = getBestPair(rootElements, metaElement);
           
            if (pair == null)
              continue;    // can't open this element
           
            // there must be a behaviour for this meta element!
            changed |= checkOrAddOpenBehaviour(doc, node, pair);
           
            // check readonly labels contained within
            IterableElementList labels = xpath(node, "labels[@readOnly='true']");
           
            for (Element label : labels) {
             
              try {
                changed |= checkOrAddOpenBehaviour(doc, label, pair);
              } catch (Throwable t) {
                String labelName = label.getAttribute("editPartClassName");
                throw new RuntimeException("Label " + labelName + ": " + t.getMessage(), t);
              }
             
            }


          } catch (Throwable t) {
            throw new RuntimeException(node.getAttribute("editPartClassName") + ": " + t.getMessage(), t);
          }
        } 
       
        if (changed) {
          saveDocument(doc, filename);
        }
      }
     
      /**
       * Checks the given node (can either be a /node, /link or /label)
       * that it contains the given OpenDiagramBehaviour. Adds it if it
       * doesn't exist, otherwise check that it matches what it should be.
       *
       * @param doc The root document
       * @param node The node to check for behaviour containment
       * @param pair The RootElementPair pointing to the editor it should open
       * @return true if the document has been modified, false otherwise
       * @throws XPathExpressionException
       */
      private boolean checkOrAddOpenBehaviour(Document doc, Element node, RootElementPair pair) throws XPathExpressionException {
        IterableElementList beh = xpath(node, "behaviour");
        assertFalse("Too many behaviours for " + node, beh.size() > 1);
       
        String policyName = camelCase(getName(pair.getFilename())) + "OpenDiagramEditPolicy";
        String diagramKind = pair.getModelID();
        String editorId = getPluginName(pair.getFilename()) + ".part.IamlDiagramEditorID";

        if (beh.size() == 1) {
          // check it is correct
          Element b = beh.item(0);
          assertEquals("gmfgen:OpenDiagramBehaviour", b.getAttribute("xsi:type"));
          assertEquals(policyName, b.getAttribute("editPolicyClassName"));
          assertEquals(diagramKind, b.getAttribute("diagramKind"));
          assertEquals(editorId, b.getAttribute("editorID"));
         
        } else if (beh.size() == 0) {
          // there is none; insert one
          log("Adding new behaviour " + policyName);
         
          Element behaviour = doc.createElement("behaviour");
          behaviour.setAttribute("xsi:type", "gmfgen:OpenDiagramBehaviour");
          behaviour.setAttribute("editPolicyClassName", policyName);
          behaviour.setAttribute("diagramKind", diagramKind);
          behaviour.setAttribute("editorID", editorId);
         
          node.appendChild(behaviour);

          return true;
        }
        return false;

      }
     
    });
   
  }

  /**
   * What should be the element that will open the given element?
   *
   * @param rootElements
   * @param metaElement
   * @return the pair or null if it shouldn't be opened
   */
  private RootElementPair getBestPair(
      List<RootElementPair> rootElements, EClass metaElement) {
   
    RootElementPair best = null;
    for (RootElementPair pair : rootElements) {
      if (pair.getElement().isSuperTypeOf(metaElement)) {
        if (best == null || best.getElement().isSuperTypeOf(pair.getElement())) {
          best = pair;
        }
      }
    }
   
    return best;
  }

  /**
   * Tests {@link #getBestPair(List, EClass)}.
   */
  public void testGetBestPair() {
    EClass domain_schema = DomainPackage.eINSTANCE.getDomainType();
    EClass role = UsersPackage.eINSTANCE.getRole();
   
    List<RootElementPair> elements = new ArrayList<RootElementPair>();
   
    // only DomainSchema
    elements.add(new RootElementPair(domain_schema, null, null));   
    assertEqualsPair(domain_schema, getBestPair(elements, domain_schema));
    assertEqualsPair(domain_schema, getBestPair(elements, role));
   
    // add Role
    elements.add(new RootElementPair(role, null, null));   
    assertEqualsPair(role, getBestPair(elements, role));
    assertEqualsPair(domain_schema, getBestPair(elements, domain_schema));

    // add Role
    assertEqualsPair(role, getBestPair(elements, role));
    assertEqualsPair(domain_schema, getBestPair(elements, domain_schema));
   
    elements.clear();
    assertEqualsPair(null, getBestPair(elements, role));
    assertEqualsPair(null, getBestPair(elements, domain_schema));

  }
 
  private void assertEqualsPair(EClass a,
      RootElementPair pair) {
    if (a == null)
      assertNull(pair);
    else
      assertEquals(a, pair.getElement());
  }

  /**
   * For every editor instance, every subclass of the
   * root diagram element should be openable in every editor.
   *
   * @throws Exception
   */
  public void testAllOpenableElementsAreOpenable() throws Exception {
    for (String filename : getGenList()) {
      Document doc = getCache().get(filename);
      Element root = xpathFirst(doc, "/GenEditorGenerator");
      String modelID = root.getAttribute("modelID");
      Element domainDiagramElement = xpathFirst(doc, "/GenEditorGenerator/diagram/domainDiagramElement");
       
      String href = domainDiagramElement.getAttribute("href");
      // trim to last /
      href = href.substring(href.lastIndexOf("/") + 1);
       
      EClass rootElement = resolveSimpleEClass(href);
     
      assertAllOpenableElements(modelID, rootElement);
    }
  }

  /**
   * Check through all .gmfgens and make sure all nodes and
   * links of subclass [rootElement] have an open behaviour
   * to [modelID].
   *
   * @param modelID
   * @param rootElement
   * @throws Exception
   */
  private void assertAllOpenableElements(String modelID, EClass rootElement) throws XPathExpressionException, Exception {
    for (String filename : getGenList()) {
      try {
      Document doc = getCache().get(filename);
     
      // will do both links and nodes
      IterableElementList nodes = xpath(doc, "/GenEditorGenerator/diagram/topLevelNodes");
      nodes.addAll(xpath(doc, "/GenEditorGenerator/diagram/links"));
      assertFalse(filename + ": No nodes found", nodes.isEmpty());
     
      for (Element node : nodes) {
        // find the meta element for this node
        Element meta = xpathFirst(node, "modelFacet/metaClass");
        // iaml.genmodel#//model/CompositeOperation
        String metaHref = meta.getAttribute("href");
        // CompositeOperation
        metaHref = metaHref.substring(metaHref.lastIndexOf("/") + 1);
       
        EClass metaElement = resolveSimpleEClass(metaHref);
       
        if (rootElement.isSuperTypeOf(metaElement)) {
          // there must be a behaviour for this meta element!
          boolean found = false;
         
          IterableElementList beh = xpath(node, "behaviour");
          String foundType = null;
          for (Element b : beh) {
            if (b.getAttribute("xsi:type").equals("gmfgen:OpenDiagramBehaviour")) {
              // found it directly
              foundType = b.getAttribute("diagramKind");
              if (b.getAttribute("diagramKind").equals(modelID)) {
                found = true;
              }
             
              // sometimes we can have multiple editors for subclasses, e.g.
              // a generic ApplicationElement editor, and a more specific
              // DomainObject editor. in this case, we need to still
              // make sure that we mark this as found when searching for
              // ApplicationElement editors
              if (!found) {
                // e.g. DomainObject
                EClass actual = getEditorEClass(filename, b.getAttribute("diagramKind"));
                if (rootElement.isSuperTypeOf(actual)) {
                  // a valid subclass
                  found = true;
                }
              }
            }
          }
         
          assertTrue(filename + ": The diagram element '" + metaHref + "' which is a subclass of '" + rootElement + "', did not have an OpenDiagramPolicy of '" + modelID + "', found: " + foundType,
              found);
        }
       
      }
      } catch (AssertionFailedError e) {
        throw new RuntimeException(filename + ": " + e.getMessage(), e);
      }
    }
  }
 
  /**
   * In each .gmfgen, each different diagram type should be unique.
   *
   * @throws Exception
   */
  public void testUniqueOpenDiagrams() throws Exception {
    for (String filename : getGenList()) {
      Document doc = getCache().get(filename);
     
      List<String> diagramKinds = new ArrayList<String>();
      List<String> editorIDs = new ArrayList<String>();
      List<String> policyNames = new ArrayList<String>();
     
      // will do both links and nodes
      IterableElementList nodes = xpath(doc, "/GenEditorGenerator/diagram/topLevelNodes");
      nodes.addAll(xpath(doc, "/GenEditorGenerator/diagram/links"));
      assertFalse(filename + ": No nodes found", nodes.isEmpty());
     
      for (Element node : nodes) {
        // does this have a behaviour?
        IterableElementList beh = xpath(node, "behaviour");
        for (Element b : beh) {
          if (b.getAttribute("xsi:type").equals("gmfgen:OpenDiagramBehaviour")) {
            String diagramKind = b.getAttribute("diagramKind");
            String editorID = b.getAttribute("editorID");
            String policyName = b.getAttribute("editPolicyClassName");
           
            if (diagramKinds.contains(diagramKind)) {
              // these should all match
              int pos = diagramKinds.indexOf(diagramKind);
             
              assertEquals(filename + ": non-unique OpenDiagram behaviour: diagramKind '"
                  + diagramKind + "'", diagramKinds.get(pos), diagramKind);
              assertEquals(filename + ": non-unique OpenDiagram behaviour: editorID '"
                  + editorID + "'", editorIDs.get(pos), editorID);
              assertEquals(filename + ": non-unique OpenDiagram behaviour: policyName '"
                  + policyName + "'", policyNames.get(pos), policyName);
            }
          }
        }
      }
    }
  }
 
  /**
   * Make sure there is only one 'contextMenu' in the root of each
   * .gmfgen. Otherwise, there may be a situation where multiple identical
   * commands with the same ID would be generated, throwing a warning
   * "Conflict for xxx.LoadResourceAction".
   *
   */
  public void testContextMenus() throws Exception {
    for (String filename : getGenList()) {
      Document doc = getCache().get(filename);
     
      IterableElementList nodes = xpath(doc, "/GenEditorGenerator/contextMenus");
     
      assertEquals(filename + ": there should be exactly one /contextMenus", nodes.size(), 1);
    }
  }
 
  /**
   * Test that if we are using Java constraints in the .gmfgen, that we
   * always have "Inject Expression Body" set to true.
   *
   * @see http://www.jevon.org/wiki/Having_Multiple_Containments_of_the_Same_Domain_Element_in_GMF
   * @throws Exception
   */
  public void testJavaExpressionInjection() throws Exception {
    for (String filename : getGenList()) {
      Document doc = getCache().get(filename);
     
      IterableElementList javaProviders = xpath(doc, "/GenEditorGenerator/expressionProviders/providers");
     
      for (Element p : javaProviders) {
        if ("gmfgen:GenJavaExpressionProvider".equals(p.getAttribute("xsi:type"))) {
          // found a Java expression provider
          assertEquals(filename + ": injectExpressionBody should be 'true'", "true", p.getAttribute("injectExpressionBody"));
        }
      }
     
    }
  }
 
  private static final String[] REQUIRED_BUNDLES = new String[] {
    "org.openiaml.model.diagram.helpers",
    "org.eclipse.xsd",
  };

  /**
   * Issue 173: add extension plugins to .gmfgen Required Plugin Identifiers
   * automatically.
   *
   * @throws Exception
   */
  public void testRequiredPluginIdentifiers() throws Exception {
    iterate(new DefaultIterator() {

      @Override
      public void execute2(String filename, Document doc)
          throws Exception {
       
        // first, let's try and add it if it doesn't already exist
        boolean changed = false;
        for (String bundle : REQUIRED_BUNDLES) {
          Element e = hasXpathFirst(doc, "/GenEditorGenerator/plugin/requiredPlugins[text()='" + bundle + "']");
          if (e == null) {
            Element root = xpathFirst(doc, "/GenEditorGenerator/plugin");
            Element n = doc.createElement("requiredPlugins");
            n.setTextContent(bundle);
            root.appendChild(n);
            changed = true;
          }
        }

        // save
        if (changed) {
          saveDocument(doc, filename);
        }
       
        // then recheck
        for (String bundle : REQUIRED_BUNDLES) {
          Element e = hasXpathFirst(doc, "/GenEditorGenerator/plugin/requiredPlugins[text()='" + bundle + "']");
          assertNotNull(filename + ": has no requiredPlugins '" + bundle + "'", e);
        }
       
      }
     
    });
  }
 
  /**
   * Issue 110: diagram editors need to have their own "new wizard" group.
   *
   * @throws Exception
   */
  public void testCreationWizardCategoryID() throws Exception {
    final String expected = "org.openiaml.model.newWizards";
   
    iterate(new DefaultIterator() {

      @Override
      public void execute2(String filename, Document doc)
          throws Exception {
       
        {
          Element root = xpathFirst(doc, "/GenEditorGenerator/diagram");
          assertNotNull(root);
         
          if (!expected.equals(root.getAttribute("creationWizardCategoryID"))) {
            root.setAttribute("creationWizardCategoryID", expected);
           
            // try modifying it
            saveDocument(doc, filename);
          }
        }
       
        // then recheck it
        Element root = xpathFirst(doc, "/GenEditorGenerator/diagram");
        assertEquals(filename + ": creationWizardCategoryID could not be fixed", expected, root.getAttribute("creationWizardCategoryID"));
      }
     
    });
  }
 
  /**
   * If you specify your own Font style in a .gmfgraph, by default the generated
   * .gmfgen will have "fixed font" set to true for this node. This prevents font styles
   * being applied (e.g. stereotype underline: issue 192; or the appearance tab being
   * disabled).
   *
   * <p>See http://www.jevon.org/wiki/GMF_Troubleshooting_9
   *
   * @throws Exception
   */
  public void testFontsAreNotFixed() throws Exception {
    iterate(new DefaultIterator() {

      @Override
      public void execute2(String filename, Document doc)
          throws Exception {
       
        // first, let's try and add it if it doesn't already exist
        boolean changed = false;
        {
          IterableElementList attributes = xpath(doc, "//topLevelNodes/viewmap/attributes");
          assertNotSame("Found no fixed labels in " + filename, 0, attributes.size());
          for (Element e : attributes) {
            if (!"false".equals(e.getAttribute("fixedFont"))) {
              // force changed to 'false'
              e.setAttribute("fixedFont", "false");
              changed = true;
            }
          }
        }

        // save
        if (changed) {
          saveDocument(doc, filename);
        }
       
        // then recheck
        {
          IterableElementList attributes = xpath(doc, "//topLevelNodes/viewmap/attributes");
          assertNotSame(0, attributes.size());
          for (Element e : attributes) {
            assertEquals(filename, "false", e.getAttribute("fixedFont"));
          }
        }
       
      }
     
    });
  }
 
  /**
   * Allows an int to be accessed in an inner class.
   */
  private class IntegerHolder {
    public int value = 0;
  }

  /**
   * Only one Domain Model Navigator is generated. This is necessary
   * to ensure that the project navigator listings are kept consistent:
   * http://www.jevon.org/wiki/GMF_Troubleshooting_3
   * @throws Exception
   */
  public void testOnlyOneDomainModelNavigator() throws Exception {
    final IntegerHolder holder = new IntegerHolder();
    holder.value = 0;
   
    iterate(new DefaultIterator() {

      @Override
      public void execute2(String filename, Document doc)
          throws Exception {
       
       
        // first, let's try and add it if it doesn't already exist
        boolean changed = false;
        if (filename.endsWith("/root.gmfgen")) {
          holder.value++;
         
          // check that generateDomainModelNavigator is either true or not set
          IterableElementList nav = xpath(doc, "/GenEditorGenerator/navigator");
          assertEquals("Only one <navigator> expected", 1, nav.size());
          for (Element e : nav) {
            if (e.hasAttribute("generateDomainModelNavigator") && !"true".equals(e.getAttribute("generateDomainModelNavigator"))) {
              // force change to 'true'
              e.setAttribute("generateDomainModelNavigator", "true");
            }
          }
        } else {
          // check that generateDomainModelNavigator is either true or not set
          IterableElementList nav = xpath(doc, "/GenEditorGenerator/navigator");
          assertEquals("Only one <navigator> expected", 1, nav.size());
          for (Element e : nav) {
            if (!e.hasAttribute("generateDomainModelNavigator") || !"false".equals(e.getAttribute("generateDomainModelNavigator"))) {
              // force change to 'false'
              e.setAttribute("generateDomainModelNavigator", "false");
            }
          }
        }
       
        // save
        if (changed) {
          saveDocument(doc, filename);
        }
       
        // then recheck
        if (filename.endsWith("/root.gmfgen")) {
          // check that generateDomainModelNavigator is either true or not set
          IterableElementList nav = xpath(doc, "/GenEditorGenerator/navigator");
          assertEquals("Only one <navigator> expected", 1, nav.size());
          for (Element e : nav) {
            if (e.hasAttribute("generateDomainModelNavigator")) {
              assertEquals(filename, "true", e.getAttribute("generateDomainModelNavigator"));
            }
          }
        } else {
          // check that generateDomainModelNavigator is either true or not set
          IterableElementList nav = xpath(doc, "/GenEditorGenerator/navigator");
          assertEquals("Only one <navigator> expected", 1, nav.size());
          for (Element e : nav) {
            assertTrue(filename, e.hasAttribute("generateDomainModelNavigator"));
            assertEquals(filename, "false", e.getAttribute("generateDomainModelNavigator"));
          }
        }

       
      }
     
    });
   
    assertEquals("One diagram editor with a filename of root.gmfgen must be found", 1, holder.value);
  }
 
}
TOP

Related Classes of org.openiaml.model.tests.release.GmfGenTestCase$IntegerHolder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.