001/** 002 * Copyright 2005-2014 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.kns.workflow; 017 018import org.apache.commons.lang.exception.ExceptionUtils; 019import org.junit.Assert; 020import org.junit.Test; 021import org.kuali.rice.core.api.uif.RemotableAttributeError; 022import org.kuali.rice.core.api.util.type.KualiDecimal; 023import org.kuali.rice.kew.api.document.search.DocumentSearchCriteria; 024import org.kuali.rice.kew.api.document.search.DocumentSearchResults; 025import org.kuali.rice.kew.api.exception.WorkflowException; 026import org.kuali.rice.kew.docsearch.service.DocumentSearchService; 027import org.kuali.rice.kew.doctype.bo.DocumentType; 028import org.kuali.rice.kew.service.KEWServiceLocator; 029import org.kuali.rice.kim.api.services.KimApiServiceLocator; 030import org.kuali.rice.krad.UserSession; 031import org.kuali.rice.krad.datadictionary.exception.UnknownDocumentTypeException; 032import org.kuali.rice.krad.service.DocumentService; 033import org.kuali.rice.krad.service.KRADServiceLocatorWeb; 034import org.kuali.rice.krad.test.document.AccountWithDDAttributesDocument; 035import org.kuali.rice.krad.util.GlobalVariables; 036import org.kuali.rice.kns.workflow.attribute.DataDictionarySearchableAttribute; 037import org.kuali.rice.krad.test.KRADTestCase; 038 039import java.sql.Timestamp; 040import java.util.ArrayList; 041import java.util.Calendar; 042import java.util.Collections; 043import java.util.HashMap; 044import java.util.List; 045import java.util.Map; 046import java.util.concurrent.Callable; 047 048import static junit.framework.Assert.assertEquals; 049import static junit.framework.Assert.fail; 050 051/** 052 * DataDictionarySearchableAttributeTest performs various DataDictionarySearchableAttribute-related tests on the doc search, including verification of proper wildcard functionality 053 * 054 * @author Kuali Rice Team (rice.collab@kuali.org) 055 * 056 * @deprecated KNS test class, convert to KRAD equivalent if applicable. 057 */ 058@Deprecated 059public class DataDictionarySearchableAttributeTest extends KRADTestCase { 060 061 @Override 062 public void setUp() throws Exception { 063 super.setUp(); 064 GlobalVariables.setUserSession(new UserSession("quickstart")); 065 } 066 067 private final static String ACCOUNT_WITH_DD_ATTRIBUTES_DOCUMENT_NAME = "AccountWithDDAttributes"; 068 069 enum DOCUMENT_FIXTURE { 070 NORMAL_DOCUMENT("Testing NORMAL_DOCUMENT", new Integer(1234567890), "John Doe", new KualiDecimal(501.77), createTimestamp( 071 2009, Calendar.OCTOBER, 15, 0, 0, 0), createTimestamp(2009, Calendar.NOVEMBER, 1, 0, 0, 0), "SecondState", true), 072 ZERO_NUMBER_DOCUMENT("Testing ZERO_NUMBER_DOCUMENT", new Integer(0), "Jane Doe", new KualiDecimal(-100), createTimestamp( 073 2009, Calendar.OCTOBER, 16, 0, 0, 0), createTimestamp(2015, Calendar.NOVEMBER, 2, 0, 0, 0), "FirstState", true), 074 FALSE_AWAKE_DOCUMENT("Testing FALSE_AWAKE_DOCUMENT", new Integer(987654321), "John D'oh", new KualiDecimal(0.0), createTimestamp( 075 2006, Calendar.OCTOBER, 17, 0, 0, 0), createTimestamp(1900, Calendar.NOVEMBER, 3, 0, 0, 0), "FourthState", false), 076 ODD_NAME_DOCUMENT("Testing ODD_NAME_DOCUMENT", new Integer(88), "_", new KualiDecimal(10000051.0), createTimestamp( 077 2009, Calendar.OCTOBER, 18, 0, 0, 0), createTimestamp(2009, Calendar.NOVEMBER, 4, 0, 0, 0), "FourthState", true), 078 ODD_TIMESTAMP_DOCUMENT("Testing ODD_TIMESTAMP_DOCUMENT", new Integer(9000), "Shane Kloe", new KualiDecimal(4.54), createTimestamp( 079 2012, Calendar.OCTOBER, 19, 0, 0, 0), createTimestamp(2007, Calendar.NOVEMBER, 5, 12, 4, 38), "ThirdState", false), 080 ANOTHER_ODD_NAME_DOCUMENT("Testing ANOTHER_ODD_NAME_DOCUMENT", new Integer(1234567889), "---", new KualiDecimal(501), createTimestamp( 081 2009, Calendar.APRIL, 20, 0, 0, 0), createTimestamp(2009, Calendar.NOVEMBER, 6, 12, 59, 59), "ThirdState", true), 082 INVALID_STATE_DOCUMENT("Testing INVALID_STATE_DOCUMENT", new Integer(99999), "AAAAAAAAA", new KualiDecimal(2.22), createTimestamp( 083 2009, Calendar.OCTOBER, 21, 0, 0, 0), createTimestamp(2009, Calendar.NOVEMBER, 7, 0, 0, 1), "SeventhState", true), 084 WILDCARD_NAME_DOCUMENT("Testing WILDCARD_NAME_DOCUMENT", new Integer(1), "Sh*ne><K!=e?", new KualiDecimal(771.05), createTimestamp( 085 2054, Calendar.OCTOBER, 22, 0, 0, 0), createTimestamp(2008, Calendar.NOVEMBER, 8, 12, 0, 0), "FirstState", true); 086 087 private String accountDocumentDescription; 088 private Integer accountNumber; 089 private String accountOwner; 090 private KualiDecimal accountBalance; 091 private Timestamp accountOpenDate; 092 private Timestamp accountUpdateDateTime; 093 private String accountState; 094 private boolean accountAwake; 095 096 private DOCUMENT_FIXTURE(String accountDocumentDescription, Integer accountNumber, String accountOwner, KualiDecimal accountBalance, Timestamp accountOpenDate, Timestamp accountUpdateDateTime, String accountState, boolean accountAwake) { 097 this.accountDocumentDescription = accountDocumentDescription; 098 this.accountNumber = accountNumber; 099 this.accountOwner = accountOwner; 100 this.accountBalance = accountBalance; 101 this.accountOpenDate = accountOpenDate; 102 this.accountUpdateDateTime = accountUpdateDateTime; 103 this.accountState = accountState; 104 this.accountAwake = accountAwake; 105 } 106 107 public AccountWithDDAttributesDocument getDocument(DocumentService docService) throws WorkflowException { 108 AccountWithDDAttributesDocument acctDoc = (AccountWithDDAttributesDocument) docService.getNewDocument(ACCOUNT_WITH_DD_ATTRIBUTES_DOCUMENT_NAME); 109 acctDoc.getDocumentHeader().setDocumentDescription(this.accountDocumentDescription); 110 acctDoc.setAccountNumber(this.accountNumber); 111 acctDoc.setAccountOwner(this.accountOwner); 112 acctDoc.setAccountBalance(this.accountBalance); 113 acctDoc.setAccountOpenDate(this.accountOpenDate); 114 acctDoc.setAccountUpdateDateTime(this.accountUpdateDateTime); 115 acctDoc.setAccountState(this.accountState); 116 acctDoc.setAccountAwake(this.accountAwake); 117 118 return acctDoc; 119 } 120 } 121 122 /** 123 * Tests the use of multi-select and wildcard searches to ensure that they function correctly for DD searchable attributes on the doc search. 124 */ 125 @Test 126 public void testWildcardsAndMultiSelectsOnDDSearchableAttributes() throws Exception { 127 DocumentService docService = KRADServiceLocatorWeb.getDocumentService(); 128 //docSearchService = KEWServiceLocator.getDocumentSearchService(); 129 DocumentType docType = KEWServiceLocator.getDocumentTypeService().findByName("AccountWithDDAttributes"); 130 String principalName = "quickstart"; 131 String principalId = KimApiServiceLocator.getPersonService().getPersonByPrincipalName(principalName).getPrincipalId(); 132 133 // Route some test documents. 134 docService.routeDocument(DOCUMENT_FIXTURE.NORMAL_DOCUMENT.getDocument(docService), "Routing NORMAL_DOCUMENT", null); 135 docService.routeDocument(DOCUMENT_FIXTURE.ZERO_NUMBER_DOCUMENT.getDocument(docService), "Routing ZERO_NUMBER_DOCUMENT", null); 136 docService.routeDocument(DOCUMENT_FIXTURE.FALSE_AWAKE_DOCUMENT.getDocument(docService), "Routing FALSE_AWAKE_DOCUMENT", null); 137 docService.routeDocument(DOCUMENT_FIXTURE.ODD_NAME_DOCUMENT.getDocument(docService), "Routing ODD_NAME_DOCUMENT", null); 138 docService.routeDocument(DOCUMENT_FIXTURE.ODD_TIMESTAMP_DOCUMENT.getDocument(docService), "Routing ODD_TIMESTAMP_DOCUMENT", null); 139 docService.routeDocument(DOCUMENT_FIXTURE.ANOTHER_ODD_NAME_DOCUMENT.getDocument(docService), "Routing ANOTHER_ODD_NAME_DOCUMENT", null); 140 docService.routeDocument(DOCUMENT_FIXTURE.INVALID_STATE_DOCUMENT.getDocument(docService), "Routing INVALID_STATE_DOCUMENT", null); 141 docService.routeDocument(DOCUMENT_FIXTURE.WILDCARD_NAME_DOCUMENT.getDocument(docService), "Routing WILDCARD_NAME_DOCUMENT", null); 142 143 // Ensure that DD searchable attribute integer fields function correctly when searched on. 144 // Note that negative numbers are disallowed by the NumericValidationPattern that validates this field. 145 assertDDSearchableAttributeWildcardsWork(docType, principalId, "accountNumber", 146 new String[] {"!1234567890", "9???9", ">1", "987654321|1234567889", "<100", ">=99999", "<=-42", ">9000|<=1", "<1|>=1234567890", 147 ">1234567889&&<1234567890", ">=88&&<=99999", "0|>10&&<10000", "9000..1000000", "0..100|>1234567889", "1..10000&&>50", "250..50"}, 148 new int[] {7 , -1 , 6 , 2 , 3 , 4 , -1 , 6 , 2, 149 0 , 3 , 3 , 2 , 4 , 2 , 0}); 150 151 // Ensure that DD searchable attribute string fields function correctly when searched on. 152 // Note that DD searchable attributes cannot treat wildcards literally, so the "Sh*ne><K!=e" case below yields very different results. 153 assertDDSearchableAttributeWildcardsWork(docType, principalId, "accountOwner", 154 new String[] {"!John Doe", "!John*", "!John Doe&&!Shane Kloe", "!Jane ???", "!Jane Doe!John Doe", "_", "_|---", "Sh*ne><K!=e", 155 ">Jane Doe", "<Shane Kloe", ">=Johnny", "<=John D'oh", ">John Doe|<---", ">=AAAAAAAAA&&<=Jane Doe", ">---&&!John D'oh", 156 "<Shane Kloe&&!John*", "*oe", "???? Doe", "Jane Doe..John Doe", "AAAAAAAAA..Shane Kloe&&!John Doe", "John D'oh|---..Jane Doe"}, 157 new int[] {7 , 6 , 6 , 7 , 6 , 1 , 2 , 8, 158 5 , 6 , 3 , 4 , 3 , 2 , 6, 159 4 , 3 , 2 , 3 , 5 , 4}); 160 161 // Ensure that DD searchable attribute float fields function correctly when searched on. Also ensure that the CurrencyFormatter is working. 162 assertDDSearchableAttributeWildcardsWork(docType, principalId, "accountBalance", 163 new String[] {"501.??", "*.54" , "!2.22", "10000051.0|771.05", "<0.0", ">501", "<=4.54", ">=-99.99", ">4.54|<=-1", ">=0&&<501.77", 164 "<=0|>=10000051", ">501&&<501.77", "-100|>771.05", "2.22..501", "-100..4.54&&<=0", "2.22|501.77..10000051.0", "Zero", 165 "-$100", "<(501)&&>=($2.22)", "$4.54|<(1)", "($0.00)..$771.05", ">=$(500)", ")501(", "4.54$", "$501..0"}, 166 new int[] {-1 , -1 , 7 , 2 , 1 , 3 , 4 , 7 , 5 , 4 , 167 3 , 0 , 2 , 3 , 2 , 4 , -1, 168 1 , 2 , 3 , 6 , -1 , -1 , -1 , 0}); 169 170 // Ensure that DD searchable attribute date fields function correctly when searched on. 171 // Note that dates with non-two-digit years outside the range of 1000 to 9999 will now fail validation. 172 assertDDSearchableAttributeWildcardsWork(docType, principalId, "accountOpenDate", 173 new String[] {"!10/15/2009", "Unknown", "10/15/2009|10/21/2009", "10/22/????", "*/*/05", ">10/17/06", "<=12-31-09&&>=10/16/2009", 174 ">101809&&<102012", ">=10/22/2054|<10/16/2009", ">2-29-12|<=10/21/09", "<2009", ">=10/19/2012|04/20/09", ">2/29/09", "2009..2008", 175 "10/15/2009..10/21/2009", "1/1/2009..10/20/2009|10/22/2054", "<=06/32/03", ">2008&&<2011|10/17/06", 176 "<02/26/10500", ">05-07-333", ">=03/26/1001", "<=11-11-9900"}, 177 new int[] {-1 , -1 , 2 , -1 , -1 , 7 , 3, 178 2 , 4 , 8 , 1 , 3 , -1 , -1, 179 4 , 5 , -1 , 6 , 180 -1 , -1 , 8 , 8}); 181 182 // Ensure that DD searchable attribute multi-select fields function correctly when searched on. 183 // Currently, an exception is *not* thrown if the value given is not among the selectable values. 184 assertDDSearchableAttributeWildcardsWork(docType, principalId, "accountStateMultiselect", 185 new String[][] {{"FirstState"}, {"SecondState"}, {"ThirdState"}, {"FourthState"}, {"FirstState","ThirdState"}, 186 {"SecondState","FourthState"}, {"ThirdState","SecondState"}, {"FourthState","FirstState","SecondState"}, {"SeventhState"}, 187 {"ThirdState","FirstState","SecondState","FourthState"}}, 188 new int[] {2 , 1 , 2 , 2 , 4, 189 3 , 3 , 5 , 1, 190 7}); 191 192 // Ensure that DD searchable attribute boolean fields function correctly when searched on. 193 // TODO: Add the commented-out boolean search expressions back in once KULRICE-3698 is complete. 194 assertDDSearchableAttributeWildcardsWork(docType, principalId, "accountAwake", new String[] {"Y", "N"}, new int[] {6, 2}); 195 /*assertDDSearchableAttributeWildcardsWork(docType, principalId, "accountAwake", 196 new String[] {"Y", "N", "Z", "Neither", "n", "y", "true", "FALSE", "fAlSe", "TrUe", "NO", "Yes", "f", "F", "T", "t", "2", "0", "1", 197 "Active", "INACTIVE", "On", "Off", "ON", "off", "EnAbLeD", "enabled", "dIsAbLeD", "DISABLED"}, 198 new int[] {6 , 2 , -1 , -1 , 2 , 6 , 6 , 2 , 2 , 6 , 2 , 6 , 2 , 2 , 6 , 6 , -1 , 2 , 6 , 199 -1 , -1 , 6 , 2 , 6 , 2 , 6 , 6 , 2 , 2});*/ 200 201 // Ensure that DD searchable attribute timestamp fields function correctly when searched on. 202 // Note that timestamps with non-two-digit years outside the range of 1000 to 9999 will now fail validation. 203 assertDDSearchableAttributeWildcardsWork(docType, principalId, "accountUpdateDateTime", 204 new String[] {"!11/01/2009 00:00:00", "11/02/2015 00:00:00|11/06/2009 12:59:59", "11/??/2009 ??:??:??", ">110609 12:59:59", 205 "<=2009 1:2:3", ">=11/06/09 12:59:59", "<11/8/2008 12:00 PM", "Blank", 206 "11/3/1900 00:00:00|>11-7-09 00:00:01", "02/29/2008 07:00:00..11/04/2009 00:00:00", 207 "11/1/09 00:00:00..11/06/09 12:59:59|11/03/1900 00:00:00", "2009..2008", "2000..2009&&>=110507 12:4:38", 208 "<=11/08/2008 12:00 AM", ">=01-01-1000 00:00:00", ">12/31/999 23:59:59", "<01-01-10000 00:00:00", "<=12/31/9999 23:59:59"}, 209 new int[] {-1 , 2 , -1 , 2, 210 3 , 3 , 2 , -1, 211 2 , 3, 212 4 , -1 , 2, 213 2 , 8 , -1 , -1 , 8}); 214 } 215 216 /** 217 * Utility method to create a timestamp quickly 218 * 219 * @param year the year of the timestamp 220 * @param month the month of the timestamp 221 * @param day the day of the timestamp 222 * @param hour the hour of the timestamp 223 * @param minute the minute of the timestamp 224 * @param second the second of the timestamp 225 * @return a new java.sql.Timestamp initialized to the precise time given 226 */ 227 private static Timestamp createTimestamp(int year, int month, int day, int hour, int minute, int second) { 228 Calendar date = Calendar.getInstance(); 229 date.set(year, month, day, hour, minute, second); 230 return new java.sql.Timestamp(date.getTimeInMillis()); 231 } 232 233 /** 234 * A convenience method for testing wildcards on data dictionary searchable attributes 235 * 236 * @param docType The document type containing the attributes. 237 * @param principalId The ID of the user performing the search. 238 * @param fieldName The name of the field on the test document. 239 * @param searchValues The search expressions to test. Has to be a String array (for regular fields) or a String[] array (for multi-select fields). 240 * @param resultSizes The number of expected documents to be returned by the search; use -1 to indicate that an error should have occurred. 241 * @throws Exception 242 */ 243 private void assertDDSearchableAttributeWildcardsWork(DocumentType docType, String principalId, String fieldName, Object[] searchValues, 244 int[] resultSizes) throws Exception { 245 if (!(searchValues instanceof String[]) && !(searchValues instanceof String[][])) { 246 throw new IllegalArgumentException("'searchValues' parameter has to be either a String[] or a String[][]"); 247 } 248 DocumentSearchCriteria.Builder criteria = null; 249 DocumentSearchResults results = null; 250 DocumentSearchService docSearchService = KEWServiceLocator.getDocumentSearchService(); 251 for (int i = 0; i < resultSizes.length; i++) { 252 criteria = DocumentSearchCriteria.Builder.create(); 253 criteria.setDocumentTypeName(docType.getName()); 254 if (searchValues instanceof String[][]) { 255 String[] innerArray = (String[]) searchValues[i]; 256 for (int j=0; j<innerArray.length; j++) { 257 criteria.addDocumentAttributeValue(fieldName, innerArray[j]); 258 } 259 } else { 260 criteria.addDocumentAttributeValue(fieldName, searchValues[i].toString()); 261 } 262 263 try { 264 results = docSearchService.lookupDocuments(principalId, criteria.build()); 265 if (resultSizes[i] < 0) { 266 Assert.fail(fieldName + "'s search at loop index " + i + " should have thrown an exception"); 267 } 268 if(resultSizes[i] != results.getSearchResults().size()){ 269 assertEquals(fieldName + "'s search results at loop index " + i + " returned the wrong number of documents.", resultSizes[i], results.getSearchResults().size()); 270 } 271 } catch (Exception ex) { 272 if (resultSizes[i] >= 0) { 273 LOG.error("exception", ex); 274 Assert.fail(fieldName 275 + "'s search at loop index " 276 + i 277 + " for search value '" 278 + searchValues[i] 279 + "' should not have thrown an exception"); 280 } 281 } 282 GlobalVariables.clear(); 283 } 284 } 285 286 /** 287 * Validates that the search inputs does not cause a class cast exception 288 */ 289 @Test 290 public void testValidateUserSearchInputsNoCast() throws Exception { 291 DataDictionarySearchableAttribute searchableAttribute = new DataDictionarySearchableAttribute(); 292 final DocumentService documentService = KRADServiceLocatorWeb.getDocumentService(); 293 294 try { 295 AccountWithDDAttributesDocument document = DOCUMENT_FIXTURE.NORMAL_DOCUMENT.getDocument(documentService); 296 documentService.saveDocument(document); 297 final String documentNumber = document.getDocumentNumber(); 298 } catch (UnknownDocumentTypeException udte) { 299 fail("CI failure - https://jira.kuali.org/browse/KULRICE-9289 " + udte.getMessage() + ExceptionUtils.getStackTrace(udte)); 300 } 301 302 Exception caughtException; 303 List foundErrors; 304 305 caughtException = null; 306 foundErrors = new ArrayList(); 307 DocumentSearchCriteria.Builder criteria = DocumentSearchCriteria.Builder.create(); 308 criteria.setDocumentTypeName(ACCOUNT_WITH_DD_ATTRIBUTES_DOCUMENT_NAME); 309 Map<String, List<String>> simpleParamMap = new HashMap<String, List<String>>(); 310 simpleParamMap.put("accountState", Collections.singletonList("FirstState")); 311 criteria.setDocumentAttributeValues(simpleParamMap); 312 try { 313 foundErrors = searchableAttribute.validateDocumentAttributeCriteria(null, criteria.build()); 314 } catch (RuntimeException re) { 315 caughtException = re; 316 } 317 Assert.assertNull("Found Exception " + caughtException, caughtException); 318 Assert.assertTrue("There were errors: " + foundErrors, (foundErrors == null || foundErrors.isEmpty())); 319 320 caughtException = null; 321 foundErrors = new ArrayList(); 322 Map<String, List<String>> listParamMap = new HashMap<String, List<String>>(); 323 List<String> paramValues = new ArrayList<String>(); 324 paramValues.add("FirstState"); 325 paramValues.add("SecondState"); 326 listParamMap.put("accountState", paramValues); 327 criteria.setDocumentAttributeValues(listParamMap); 328 try { 329 foundErrors = searchableAttribute.validateDocumentAttributeCriteria(null, criteria.build()); 330 } catch (RuntimeException re) { 331 caughtException = re; 332 } 333 Assert.assertNull("Found Exception " + caughtException, caughtException); 334 Assert.assertTrue("There were errors: " + foundErrors, (foundErrors == null || foundErrors.isEmpty())); 335 } 336 337 /** 338 * Tests handling resolution of error messages 339 */ 340 @Test 341 public void testErrorMessageResolution() throws Exception { 342 final DataDictionarySearchableAttribute searchableAttribute = new DataDictionarySearchableAttribute(); 343 final DocumentSearchCriteria.Builder criteria = DocumentSearchCriteria.Builder.create(); 344 /*criteria.setDocumentTypeName(ACCOUNT_WITH_DD_ATTRIBUTES_DOCUMENT_NAME); 345 Map<String, List<String>> simpleParamMap = new HashMap<String, List<String>>(); 346 simpleParamMap.put("accountState", Collections.singletonList("FirstState")); 347 criteria.setDocumentAttributeValues(simpleParamMap);*/ 348 List<RemotableAttributeError> errors = GlobalVariables.doInNewGlobalVariables(new Callable<List<RemotableAttributeError>>() { 349 public List<RemotableAttributeError> call() { 350 GlobalVariables.getMessageMap().putError("fake.property", "error.custom", "the error message"); 351 return searchableAttribute.validateDocumentAttributeCriteria(null, criteria.build()); 352 } 353 }); 354 Assert.assertEquals(1, errors.size()); 355 assertEquals("the error message", errors.get(0).getMessage()); 356 } 357 358 /** 359 * Test multiple value searches in the context of whole document search context 360 */ 361 @Test 362 public void testMultiSelectIntegration() throws Exception { 363 final DocumentService docService = KRADServiceLocatorWeb.getDocumentService(); 364 //docSearchService = KEWServiceLocator.getDocumentSearchService(); 365 DocumentType docType = KEWServiceLocator.getDocumentTypeService().findByName("AccountWithDDAttributes"); 366 String principalName = "quickstart"; 367 String principalId = KimApiServiceLocator.getPersonService().getPersonByPrincipalName(principalName).getPrincipalId(); 368 369 // Route some test documents. 370 docService.routeDocument(DOCUMENT_FIXTURE.NORMAL_DOCUMENT.getDocument(docService), "Routing NORMAL_DOCUMENT", null); 371 372 assertDDSearchableAttributeWildcardsWork(docType, principalId, "accountStateMultiselect", 373 new String[][] {{"FirstState"}, {"SecondState"}, {"ThirdState"}, {"FourthState"}, {"FirstState", "SecondState"}, {"FirstState","ThirdState"}, {"FirstState", "FourthState"}, {"SecondState", "ThirdState"}, {"SecondState", "FourthState"}, {"ThirdState", "FourthState"}, {"FirstState", "SecondState", "ThirdState"}, {"FirstState", "ThirdState", "FourthState"}, {"SecondState", "ThirdState", "FourthState"}, {"FirstState","SecondState", "ThirdState", "FourthState"}}, 374 new int[] { 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1 }); 375 376 assertDDSearchableAttributeWildcardsWork(docType, principalId, "accountOpenDate", 377 new String[][] {{"10/15/2009"}, {"10/15/2009","10/17/2009"}, {"10/14/2009","10/16/2009"}}, 378 new int[] { 1, 1, 0 }); 379 380 assertDDSearchableAttributeWildcardsWork(docType, principalId, "accountBalance", 381 new String[][] {{"501.77"},{"501.77", "63.54"},{"501.78","501.74"}, {"502.00"}, {"0.00"} }, 382 new int[] { 1, 1, 0, 0, 0 }); 383 384 assertDDSearchableAttributeWildcardsWork(docType, principalId, "accountNumber", 385 new String[][] {{"1234567890"},{"1234567890", "9876543210"},{"9876543210","77774"}, {"88881"}, {"0"} }, 386 new int[] { 1, 1, 0, 0, 0 }); 387 } 388}