/*
* � Copyright IBM Corp. 2013
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
/*
* Author: Maire Kehoe (mkehoe@ie.ibm.com)
* Date: 28 Jul 2011
* ForEditorTest.java
*/
package com.ibm.xsp.test.framework.registry.annotate;
import java.util.ArrayList;
import java.util.StringTokenizer;
import com.ibm.commons.util.StringUtil;
import com.ibm.xsp.registry.FacesComponentDefinition;
import com.ibm.xsp.registry.FacesDefinition;
import com.ibm.xsp.registry.FacesProperty;
import com.ibm.xsp.registry.FacesSharableRegistry;
import com.ibm.xsp.registry.RegistryUtil;
import com.ibm.xsp.registry.parse.ParseUtil;
import com.ibm.xsp.test.framework.AbstractXspTest;
import com.ibm.xsp.test.framework.TestProject;
import com.ibm.xsp.test.framework.XspTestUtil;
import com.ibm.xsp.test.framework.registry.annotate.PageEditorTest.EditorAnnotater;
import com.ibm.xsp.test.framework.registry.annotate.SpellCheckTest.DescriptionDisplayNameAnnotater;
import com.ibm.xsp.test.framework.setup.SkipFileContent;
/**
*
* @author Maire Kehoe (mkehoe@ie.ibm.com)
*/
public class ForEditorTest extends AbstractXspTest {
@Override
public String getDescription() {
// note, the editor for controls in the current XPage was added
// in 8.5.3 as part of SPR#MKEE8ECFFJ
return "that 'for'-like properties use the <editor> for picking a control id in this .xsp file";
}
public void testForEditor() throws Exception {
// note, xp:includePage "componentId" uses a different editor - the controlPicker editor.
String[] forPropertyNames = new String[]{
// "-" at start indicates suffix.
"for", // xp:label "for", xp:pager "for"
"refreshId", // xp:eventHandler "refreshId"
"targetId",
"execId", // xp:eventHandler "execId"
"inputId", // xp:typeAhead "inputId"
"modifiedControl", // xp:view "modifiedControl"
"userId", // ActivityStreams
"groupId", // ActivityStreams
"appId", // ActivityStreams
"activityId", // ActivityStreams
};
String[] forPropertyNameSuffixes = new String[]{
"Control",
"ComponentId",
"Id",
};
String[] forDisplayNameSuffixes = new String[]{
"Id",
"Control",
};
String[] forDescriptionSnippets = new String[]{
"the target control",
"the id of the",
"ID of the",
"ID of a",
"Identifies the control",
"he control that", //modifiedControl description contains "The control that"
"id of the component",
"ID of the component",
};
FacesSharableRegistry reg = TestProject.createRegistryWithAnnotater(
this, new EditorAnnotater(), new DescriptionDisplayNameAnnotater(),
new PropertyTagsAnnotater());
String fails = "";
for (FacesDefinition def : TestProject.getLibDefinitions(reg, this)) {
for (FacesProperty prop : RegistryUtil.getProperties(def,
def.getDefinedInlinePropertyNames())) {
if( !String.class.equals(prop.getJavaClass()) ){
// only look at String propertys
continue;
}
String propName = prop.getName();
String displayName = (String) prop.getExtension("display-name");
String description = (String) prop.getExtension("description");
boolean suspectedForProperty = false;
String reason = null;
if( ! suspectedForProperty ){
int index = XspTestUtil.indexOf(forPropertyNames, propName);
if( -1 != index ){
suspectedForProperty = true;
reason = "<property-name> is '" +forPropertyNames[index]+"'";
}
}
if( ! suspectedForProperty ){
int index = XspTestUtil.endsWithIndex(forPropertyNameSuffixes, propName);
if( -1 != index ){
suspectedForProperty = true;
reason = "<property-name> endsWith '" +forPropertyNameSuffixes[index]+"'";
}
}
if( ! suspectedForProperty ){
int index = XspTestUtil.endsWithIndex(forDisplayNameSuffixes, displayName);
if( -1 != index ){
suspectedForProperty = true;
reason = "<display-name> endsWith '" +forDisplayNameSuffixes[index]+"'";
}
}
if( ! suspectedForProperty ){
int index = XspTestUtil.containsSubstringIndex(forDescriptionSnippets, description);
if( -1 != index ){
suspectedForProperty = true;
reason = "<description> contains '" +forDescriptionSnippets[index]+"'";
}
}
if( suspectedForProperty ){
if( PropertyTagsAnnotater.isTagged(prop, "not-control-id-reference") ){
suspectedForProperty = false;
}
}
if( suspectedForProperty ){
// verify editor as expected
// idpicker was added in Designer 8.5.3 for SPR#MKEE8ECFFJ
// and gives a combo with all the ids in the current XPage
String expectedEditorAnyControl = "com.ibm.designer.domino.xsp.idpicker";
// XPageControlIDEditor was added in Designer 8.5.3UP1
// and gives a combo with IDs restricted to just those with the given namespace/tagNames
String expectedEditorSpecificControls = "com.ibm.xsp.extlib.designer.tooling.editor.XPageControlIDEditor";
String actualEditor = (String) prop.getExtension("editor");
boolean isMatchAnyControlEditor = expectedEditorAnyControl.equals(actualEditor);
boolean isMatchSpecificControlEditor = expectedEditorSpecificControls.equals(actualEditor);
if (!(isMatchAnyControlEditor || isMatchSpecificControlEditor)) {
fails += def.getFile().getFilePath()+ " "
+ ParseUtil.getTagRef(def) + " "
+ propName
+ " <editor> not as expected. Was: "
+ actualEditor + ", expected one of the 2 control pickers. "
+ "The property is considered 'for'-like because "
+reason+"\n";
}
String editorParamStr = (String) prop.getExtension("editor-parameter");
if( isMatchAnyControlEditor && null != editorParamStr ){
fails += def.getFile().getFilePath()+ " "
+ ParseUtil.getTagRef(def) + " "
+ propName
+ " Unexpected <editor-parameter>\n";
}
if( isMatchSpecificControlEditor ){
String[][] editorParamArr = null == editorParamStr? null : parseIdEditorParams(editorParamStr);
if( null == editorParamArr || editorParamArr.length == 0 ){
fails += def.getFile().getFilePath()+ " "
+ ParseUtil.getTagRef(def) + " "
+ propName
+ " Missing expected <editor-parameter> tag with list of namespace|tagName\n";
}else{
for (String[] namespaceAndTag : editorParamArr) {
FacesDefinition referenced = reg.findDef(namespaceAndTag[0], namespaceAndTag[1]);
if( null == referenced || !(referenced instanceof FacesComponentDefinition)
|| ! referenced.isTag() ){
fails += def.getFile().getFilePath()+ " "
+ ParseUtil.getTagRef(def) + " "
+ propName
+ " <editor-parameter> tag reference "
+ "does not resolve to a known namespace|tagName: "+
namespaceAndTag[0]+"|"+namespaceAndTag[1]+"\n";
}
} // end for
} // end else editorParam.length > 0
}
}
}
}
fails = XspTestUtil.removeMultilineFailSkips(fails,
SkipFileContent.concatSkips(getSkips(), this, "testForEditor"));
if( fails.length() > 0 ){
fail( XspTestUtil.getMultilineFailMessage(fails));
}
}
protected String[] getSkips(){
return StringUtil.EMPTY_STRING_ARRAY;
}
private String[][] parseIdEditorParams(String params){
// Same code as in design-time code that uses the params
ArrayList<String[]> controlsToInclude = new ArrayList<String[]>();
//we allow parameters separated by commas or carriage returns, so those are our tokens.
String tokens = ",\r\n"; // $NON-NLS-1$
StringTokenizer st = new StringTokenizer(params, tokens);
while (st.hasMoreTokens()) {
String line = st.nextToken().trim();
if(StringUtil.isNotEmpty(line)) {
String namespace;
String tagName;
//namespace and tagName are separated by colons.
int pos = line.indexOf("|");
if(pos>=0) {
namespace = line.substring(0,pos);
tagName = line.substring(pos+1);
}else{
namespace = null;
tagName = line;
}
controlsToInclude.add(new String[]{namespace,tagName});
}
}
return controlsToInclude.toArray(new String[controlsToInclude.size()][]);
}
}