/******************************************************************************* * Copyright (c) 2007 Exadel, Inc. and Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is 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: * Exadel, Inc. and Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.common.model.test; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import junit.framework.TestCase; import org.jboss.tools.common.meta.XChild; import org.jboss.tools.common.meta.XMapping; import org.jboss.tools.common.meta.XModelEntity; import org.jboss.tools.common.meta.XModelMetaData; import org.jboss.tools.common.meta.action.XAction; import org.jboss.tools.common.meta.action.XActionHandler; import org.jboss.tools.common.meta.action.XActionItem; import org.jboss.tools.common.meta.action.XActionList; import org.jboss.tools.common.meta.impl.XExtensions; import org.jboss.tools.common.meta.impl.XModelEntityImpl; import org.jboss.tools.common.meta.impl.XModelMetaDataImpl; import org.jboss.tools.common.model.XModel; import org.jboss.tools.common.model.XModelException; import org.jboss.tools.common.model.XModelFactory; import org.jboss.tools.common.model.XModelObject; import org.jboss.tools.common.model.engines.impl.EnginesLoader; import org.jboss.tools.common.model.event.XModelTreeEvent; import org.jboss.tools.common.model.event.XModelTreeListener; import org.jboss.tools.common.model.loaders.XObjectLoader; import org.jboss.tools.common.model.options.PreferenceModelUtilities; import org.jboss.tools.common.model.util.ModelFeatureFactory; import org.jboss.tools.common.model.util.XModelObjectLoaderUtil; public class MetaModelTest extends TestCase { public MetaModelTest() {} protected void setUp() throws Exception { } /** * Base test checking that meta model is loaded. */ public void testMetaModelLoading() { XModelMetaData meta = XModelMetaDataImpl.getInstance(); assertNotNull("Meta model is not loaded", meta); } /** * Some common implementations of XModelObject has aliases listed in * mapping named "Implementations". Check that these classes exist. */ public void testImplementationMapping() { XModelMetaData meta = XModelMetaDataImpl.getInstance(); XMapping mapping = meta.getMapping("Implementations"); String[] s = mapping.getKeys(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < s.length; i++) { String cn = mapping.getValue(s[i]); Class c = ModelFeatureFactory.getInstance().getFeatureClass(cn); if(c == null) { sb.append(s[i] + ":" + cn).append(" cannot find class").append("\n"); } else { try { XModelObject o = (XModelObject)c.newInstance(); } catch (Exception e) { sb.append(s[i] + ":" + cn).append(" - cannot assign to XModelObject").append("\n"); } } } assertTrue("Mapping 'Implementations' has wrong items.\n" + sb.toString(), sb.length() == 0); } /** * Some common action handlers of has aliases listed in * mapping named "Implementations". Check that these classes exist * and can be reduced to XActionHandler. */ public void testActionHandlersMapping() { XModelMetaData meta = XModelMetaDataImpl.getInstance(); XMapping mapping = meta.getMapping("Handlers"); String[] s = mapping.getKeys(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < s.length; i++) { String cn = mapping.getValue(s[i]); Class c = ModelFeatureFactory.getInstance().getFeatureClass(cn); if(c == null) { sb.append(s[i] + ":" + cn).append(" cannot find class").append("\n"); } else { try { XActionHandler o = (XActionHandler)c.newInstance(); } catch (Exception e) { sb.append(s[i] + ":" + cn).append(" - cannot assign to XActionHandler").append("\n"); } } } assertTrue("Mapping 'Implementations' has wrong items.\n" + sb.toString(), sb.length() == 0); } public void testEntityImplementations() { XModelMetaData meta = XModelMetaDataImpl.getInstance(); String[] entities = meta.entities(); StringBuilder sb = new StringBuilder(); int errors = 0; for (int i = 0; i < entities.length; i++) { XModelEntity entity = meta.getEntity(entities[i]); //TODO - should be tested through public interface String error = entity.testImplementation(); if(error != null) { errors++; sb.append(entity.getName()).append(" - ").append(error).append("\n"); } } assertTrue("These " + errors + " entities have wrong implementations\n" + sb.toString(), errors == 0); } /** * For each entity check that declared child entities reference existing entities. */ public void testEntityChildren() { XModelMetaData meta = XModelMetaDataImpl.getInstance(); String[] entities = meta.entities(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < entities.length; i++) { XModelEntity entity = meta.getEntity(entities[i]); XChild[] cs = entity.getChildren(); for (int j = 0; j < cs.length; j++) { if(meta.getEntity(cs[j].getName()) == null) { sb.append(entities[i] + ":" + cs[j].getName()).append("\n"); } } } assertTrue("These entity children reference unknown entities.\n" + sb.toString(), sb.length() == 0); } /** * Test that declared in action handler exists and is instanceof AbstractHandler. * For handlers that are instances of DefaultSpecialHandler, check that declared * support class exists and is instanceof SpecialWizardSupport. */ public void testActionHandlers() { XModelMetaData meta = XModelMetaDataImpl.getInstance(); String[] entities = meta.entities(); Set<String> errors = new HashSet<String>(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < entities.length; i++) { XModelEntity entity = meta.getEntity(entities[i]); collectActionsWithWrongHandlers(entity, entity.getActionList(), errors); } sb.append("These " + errors.size() + " actions have wrong handlers\n"); Iterator<String> it = errors.iterator(); while(it.hasNext()) { sb.append(it.next()).append("\n"); } assertTrue(sb.toString(), errors.size() == 0); } protected void collectActionsWithWrongHandlers(XModelEntity entity, XActionItem item, Set<String> errors) { if(item instanceof XActionList) { XActionList list = (XActionList)item; XActionItem[] is = list.getActionItems(); for (int i = 0; i < is.length; i++) collectActionsWithWrongHandlers(entity, is[i], errors); } else if(item instanceof XAction) { XAction action = (XAction)item; //TODO - should be tested through public interface String error = action.testHandler(); if(error != null) { errors.add(entity.getName() + ":" + action.getPath() + " - " + error); } //TODO - should be tested through public interface error = action.testEntityData(); if(error != null) { errors.add(entity.getName() + ":" + action.getPath() + " - " + error); } } } /** * Check that extensions reference existing entities. * This test make sense only in client plug-ins. It should be moved to jst,jsf and * others plug-ins which are using model plug-in. * */ public void fixmeTestEntityExtensions() { XModelMetaDataImpl meta = (XModelMetaDataImpl)XModelMetaDataImpl.getInstance(); XExtensions s = meta.getExtensions(); //TODO - should be tested through public interface Set set = s.test(meta); String message = "These " + set.size() + " extensions reference unknown entities\n"; Iterator it = set.iterator(); while(it.hasNext()) { message += it.next() + "\n"; } // FIXME assertTrue(message, set.size() != 0); } /** * Check icons declared in entities. */ public void testEntityIcons() { XModelMetaData meta = XModelMetaDataImpl.getInstance(); String[] entities = meta.entities(); int entitiesWithoutIcons = 0; String firstEntityWithoutIcon = null; for (int i = 0; i < entities.length; i++) { XModelEntity entity = meta.getEntity(entities[i]); String iconPath = entity.getRenderer().getIconInfo("main"); if(iconPath != null) { Object o = meta.getIconList().getImage(iconPath); if(o == null) { entitiesWithoutIcons++; if(firstEntityWithoutIcon == null) firstEntityWithoutIcon = entities[i]; } } } assertTrue("Icons for " + entitiesWithoutIcons + " entities are missing. Entity example: " + firstEntityWithoutIcon, entitiesWithoutIcons == 0); } /** * Check icons declared in actions and cascade action lists. */ public void testActionIcons() { XModelMetaData meta = XModelMetaDataImpl.getInstance(); String[] entities = meta.entities(); Set<String> actionsWithoutIcons = new HashSet<String>(); for (int i = 0; i < entities.length; i++) { XModelEntity entity = meta.getEntity(entities[i]); collectActionsWithoutIcon(entity, entity.getActionList(), actionsWithoutIcons); } StringBuffer message = new StringBuffer(); message.append("Icons for " + actionsWithoutIcons.size() + " actions are missing.\n"); Iterator<String> it = actionsWithoutIcons.iterator(); while(it.hasNext()) { message.append(" ").append(it.next()).append("\n"); } assertTrue(message.toString(), actionsWithoutIcons.size() == 0); } protected void collectActionsWithoutIcon(XModelEntity entity, XActionItem item, Set<String> actionsWithoutIcons) { String iconPath = item.getIconKey(); if(iconPath != null && item.getPath() != null && iconPath.length() > 0 && (!(item instanceof XActionList) || ((XActionList)item).getGroupFactor() == 1)) { Object o = item.getMetaModel().getIconList().getImage(iconPath); if(o == null) { actionsWithoutIcons.add("ActionPath=" + entity.getName() + ":" + item.getPath() + " iconPath=" + iconPath); } } else { } if(item instanceof XActionList) { XActionList list = (XActionList)item; XActionItem[] is = list.getActionItems(); for (int i = 0; i < is.length; i++) collectActionsWithoutIcon(entity, is[i], actionsWithoutIcons); } } /** * One everywhere available instance of model is preferences model. * Check that it returns non-null instance. */ public void testPreferencesModel() { XModel model = PreferenceModelUtilities.getPreferenceModel(); assertTrue("Cannot load preferences model", model != null); } /** * Try to create instance of model object for each entity that declares implementing class. */ public void testCreatingModelObjects() { XModelMetaData meta = XModelMetaDataImpl.getInstance(); XModel model = XModelFactory.getDefaultInstance(); String[] entities = meta.entities(); StringBuilder sb = new StringBuilder(); int errors = 0; for (int i = 0; i < entities.length; i++) { XModelEntityImpl entity = (XModelEntityImpl)meta.getEntity(entities[i]); if(entity.hasObjectImplementation()) { XModelObject object = model.createModelObject(entity.getName(), null); if(object == null) { errors++; sb.append(entity.getName()).append("\n"); } } } assertTrue("Model objects for " + errors + " entities cannot be created\n" + sb.toString(), errors == 0); } /** * Test loaders for all entities. If entity declares loader that cannot be created * and reduced to XObjectLoader, report error. * For entities that represent file objects, create loader and model object instances, * and do save/load, than compare initial object to object restored on loading. * If these objects are not identical, report error. * TASK: It is good to have initial object as loaded from a large example file, * rather than just created 'empty' object. To provide for that, we can for example * introduce attribute 'example' to entity. */ public void testObjectLoaders() { XModel model = XModelFactory.getDefaultInstance(); XModelMetaData meta = XModelMetaDataImpl.getInstance(); String[] entities = meta.entities(); StringBuilder sb = new StringBuilder(); int errors = 0; for (int i = 0; i < entities.length; i++) { XModelEntity entity = meta.getEntity(entities[i]); //TODO - should be tested through public interface String error = entity.testLoader(); if(error != null) { errors++; sb.append(entity.getName()).append(" - ").append(error).append("\n"); } else { if(!entity.hasObjectLoader()) continue; XModelObject object = XModelObjectLoaderUtil.createValidObject(model, entity.getName()); if(object == null) { continue; } XObjectLoader loader = XModelObjectLoaderUtil.getObjectLoader(object); if(object.getFileType() == XModelObject.FILE) { object.setModified(true); loader.save(object); String body = XModelObjectLoaderUtil.getTempBody(object); if(body == null) { errors++; sb.append(entity.getName()).append(" - ").append(" cannot save").append("\n"); } else { XModelObject object2 = XModelObjectLoaderUtil.createValidObject(model, entity.getName()); XModelObjectLoaderUtil.setTempBody(object2, body); loader.load(object2); MergeListener m = new MergeListener(model); try { EnginesLoader.merge(object, object2); } catch (XModelException e) { fail(e.getMessage()); } m.dispose(); if(!m.equal) { errors++; sb.append(entity.getName()).append(" - ").append(" save/load corrupts object").append("\n"); } } } } } assertTrue("These " + errors + " entities have wrong loaders\n" + sb.toString(), errors == 0); } class MergeListener implements XModelTreeListener { XModel model; boolean equal = true; public MergeListener(XModel model) { this.model = model; model.addModelTreeListener(this); } public void nodeChanged(XModelTreeEvent event) { equal = false; } public void structureChanged(XModelTreeEvent event) { equal = false; } public void dispose() { model.removeModelTreeListener(this); } } }