1 /*
   2  * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2019, BELLSOFT. All rights reserved.
   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   6  * This code is free software; you can redistribute it and/or modify it
   7  * under the terms of the GNU General Public License version 2 only, as
   8  * published by the Free Software Foundation.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 
  26 package compiler.intrinsics.string.indexof;
  27 
  28 // Basic class for indexof testing. Check all possible pattern size and index
  29 // up to source string size specified via command line. Expected to run with
  30 // different source size according to platform indexof implementation specifics.
  31 // Run with Xcomp, because execution until compilation can take too long in case
  32 // of large argument.
  33 public class TestIndexOf {
  34     private static final char PADDING = 'A';
  35 
  36     public static void main(String[] args) {
  37         TestIndexOf test = new TestIndexOf();
  38         int sourceSize = Integer.parseInt(args[0]);
  39         test.checkForSourceSizeUU(sourceSize); // UTF-16 source, UTF-16 pattern
  40         test.checkForSourceSizeUL(sourceSize); // UTF-16 source, Latin1 pattern
  41         test.checkForSourceSizeLL(sourceSize); // Latin1 source, Latin1 pattern
  42     }
  43 
  44     // check UTF-16 pattern search in UTF-16 source using specifiec source size
  45     private void checkForSourceSizeUU(int sourceSize) {
  46         String strUTF16 = generateSourceString(sourceSize, /* isUTF16 = */ true);
  47         for (int patternSize = 1; patternSize < sourceSize; patternSize++) {
  48             String uniquePatternUTF16 = generatePatternString(patternSize,
  49                     /* isUTF16 */ true, /* usePadding = */ false);
  50             String partialMatchPatternUTF16 = generatePatternString(patternSize,
  51                     /* isUTF16 */ true, /* usePadding = */ true);
  52             for (int index = -1; index <= sourceSize-patternSize; index++) {
  53                 testCase(strUTF16, uniquePatternUTF16, index); // no partial match
  54                 testCase(strUTF16, partialMatchPatternUTF16, index); // has partial match
  55             }
  56         }
  57     }
  58 
  59     // check Latin1 pattern search in UTF-16 source using specifiec source size
  60     private void checkForSourceSizeUL(int sourceSize) {
  61         String strUTF16 = generateSourceString(sourceSize, /* isUTF16 = */ true);
  62         for (int patternSize = 1; patternSize < sourceSize; patternSize++) {
  63             String uniquePatternLatin1 = generatePatternString(patternSize,
  64                     /* isUTF16 */ false, /* usePadding = */ false);
  65             String partialMatchPatternLatin1 = generatePatternString(patternSize,
  66                     /* isUTF16 */ false, /* usePadding = */ true);
  67             for (int index = -1; index <= sourceSize-patternSize; index++) {
  68                 testCase(strUTF16, uniquePatternLatin1, index); // no partial match
  69                 testCase(strUTF16, partialMatchPatternLatin1, index); // has partial match
  70             }
  71         }
  72     }
  73 
  74     // check Latin1 pattern search in Latin1 source using specifiec source size
  75     private void checkForSourceSizeLL(int sourceSize) {
  76         String strLatin1 = generateSourceString(sourceSize, /* isUTF16 = */ false);
  77         for (int patternSize = 1; patternSize < sourceSize; patternSize++) {
  78             String uniquePatternLatin1 = generatePatternString(patternSize,
  79                     /* isUTF16 */ false, /* usePadding = */ false);
  80             String partialMatchPatternLatin1 = generatePatternString(patternSize,
  81                     /* isUTF16 */ false, /* usePadding = */ true);
  82             for (int index = -1; index <= sourceSize-patternSize; index++) {
  83                 testCase(strLatin1, uniquePatternLatin1, index); // no partial match
  84                 testCase(strLatin1, partialMatchPatternLatin1, index); // has partial match
  85             }
  86         }
  87     }
  88 
  89     private void testCase(String srcTemplate, String patternString, int index) {
  90         String searchString = srcTemplate;
  91         if (index != -1) {
  92             // case when srcTemplate and patternString length is equal, 
  93             // encoding is UTF16(src) and Latin1(pattern) and expected match
  94             // index is 0 will trigger case of Lating1 source string.
  95             searchString  = srcTemplate.substring(0, index) + patternString
  96                     + srcTemplate.substring(index + patternString.length());
  97         }
  98         int result = searchString.indexOf(patternString);
  99         if (result != index) {
 100             throw new AssertionError("Unexpected index: " + result
 101                     + " searching '" + patternString + "' in '" + searchString);
 102         }
 103     }
 104 
 105     // create string with given length and Latin1/UTF16 encoding. Consists
 106     // mostly of PADDING char.
 107     private String generateSourceString(int length, boolean isUTF16) {
 108         char[] raw = new char[length];
 109         for (int i = 0; i < length; i++) {
 110             raw[i] = PADDING;
 111         }
 112         if (isUTF16) {
 113           raw[0] = '\uCAFE';
 114           raw[length - 1] = '\uBABE';
 115         }
 116         return new String(raw);
 117     }
 118 
 119     // create pattern string with given length, Latin1/UTF16 encoding and
 120     // consisting mostly of PADDING chars in case of usePadding is true.
 121     private String generatePatternString(int length, boolean isUTF16, boolean usePadding) {
 122         char[] raw = new char[length];
 123         char baseChar = isUTF16 ? '\uABCD' : 'C';
 124         for (int i = 0; i < length - 1; i++) {
 125             raw[i] = usePadding ? PADDING : (char)(baseChar % 40);
 126         }
 127         raw[length - 1] = isUTF16 ? '\uBEEF' : 'B';
 128         return new String(raw);
 129     }
 130 }