diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:28:47 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:28:47 -0800 |
commit | adc854b798c1cfe3bfd4c27d68d5cee38ca617da (patch) | |
tree | 6aed8b4923ca428942cbaa7e848d50237a3d31e0 /regex | |
parent | 1c0fed63c71ddb230f3b304aac12caffbedf2f21 (diff) | |
download | libcore-adc854b798c1cfe3bfd4c27d68d5cee38ca617da.zip libcore-adc854b798c1cfe3bfd4c27d68d5cee38ca617da.tar.gz libcore-adc854b798c1cfe3bfd4c27d68d5cee38ca617da.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'regex')
20 files changed, 9086 insertions, 0 deletions
diff --git a/regex/MODULE_LICENSE_APACHE2 b/regex/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/regex/MODULE_LICENSE_APACHE2 diff --git a/regex/src/main/java/java/util/regex/MatchResult.java b/regex/src/main/java/java/util/regex/MatchResult.java new file mode 100644 index 0000000..fa67ba6 --- /dev/null +++ b/regex/src/main/java/java/util/regex/MatchResult.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * 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. + */ + +package java.util.regex; + +/** + * Holds the results of a successful match of a {@link Pattern} against a + * given string. The result is divided into groups, with one group for each + * pair of parentheses in the regular expression and an additional group for + * the whole regular expression. The start, end, and contents of each group + * can be queried. + * + * @see Matcher + * @see Matcher#toMatchResult() + * + * @since Android 1.0 + */ +public interface MatchResult { + + /** + * Returns the index of the first character following the text that matched + * the whole regular expression. + * + * @return the character index. + * + * @since Android 1.0 + */ + int end(); + + /** + * Returns the index of the first character following the text that matched + * a given group. + * + * @param group + * the group, ranging from 0 to groupCount() - 1, with 0 + * representing the whole pattern. + * + * @return the character index. + * + * @since Android 1.0 + */ + int end(int group); + + /** + * Returns the text that matched the whole regular expression. + * + * @return the text. + * + * @since Android 1.0 + */ + String group(); + + /** + * Returns the text that matched a given group of the regular expression. + * + * @param group + * the group, ranging from 0 to groupCount() - 1, with 0 + * representing the whole pattern. + * + * @return the text that matched the group. + * + * @since Android 1.0 + */ + String group(int group); + + /** + * Returns the number of groups in the result, which is always equal to + * the number of groups in the original regular expression. + * + * @return the number of groups. + * + * @since Android 1.0 + */ + int groupCount(); + + /** + * Returns the index of the first character of the text that matched + * the whole regular expression. + * + * @return the character index. + * + * @since Android 1.0 + */ + int start(); + + /** + * Returns the index of the first character of the text that matched a given + * group. + * + * @param group + * the group, ranging from 0 to groupCount() - 1, with 0 + * representing the whole pattern. + * + * @return the character index. + * + * @since Android 1.0 + */ + int start(int group); +} diff --git a/regex/src/main/java/java/util/regex/MatchResultImpl.java b/regex/src/main/java/java/util/regex/MatchResultImpl.java new file mode 100644 index 0000000..795f2f6 --- /dev/null +++ b/regex/src/main/java/java/util/regex/MatchResultImpl.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * 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. + */ + +package java.util.regex; + +/** + * Holds the results of a successful match of a regular expression against a + * given string. Only used internally, thus sparsely documented (though the + * defining public interface has full documentation). + * + * @see java.util.regex.MatchResult + */ +class MatchResultImpl implements MatchResult { + + /** + * Holds the original input text. + */ + private String text; + + /** + * Holds the offsets of the groups in the input text. The first two + * elements specifiy start and end of the zero group, the next two specify + * group 1, and so on. + */ + private int[] offsets; + + MatchResultImpl(String text, int[] offsets) { + this.text = text; + this.offsets = offsets.clone(); + } + + public int end() { + return end(0); + } + + public int end(int group) { + return offsets[2 * group + 1]; + } + + public String group() { + return text.substring(start(), end()); + } + + public String group(int group) { + int from = offsets[group * 2]; + int to = offsets[(group * 2) + 1]; + if (from == -1 || to == -1) { + return null; + } else { + return text.substring(from, to); + } + } + + public int groupCount() { + return (offsets.length / 2) - 1; + } + + public int start() { + return start(0); + } + + public int start(int group) { + return offsets[2 * group]; + } + +} diff --git a/regex/src/main/java/java/util/regex/Matcher.java b/regex/src/main/java/java/util/regex/Matcher.java new file mode 100644 index 0000000..e3e4874 --- /dev/null +++ b/regex/src/main/java/java/util/regex/Matcher.java @@ -0,0 +1,779 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * 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. + */ + +package java.util.regex; + +import com.ibm.icu4jni.regex.NativeRegEx; + +/** + * Provides a means of matching regular expressions against a given input, + * finding occurrences of regular expressions in a given input, or replacing + * parts of a given input. A {@code Matcher} instance has an associated {@link + * Pattern} instance and an input text. A typical use case is to + * iteratively find all occurrences of the {@code Pattern}, until the end of + * the input is reached, as the following example illustrates: + * + * <p/> + * + * <pre> + * Pattern p = Pattern.compile("[A-Za-z]+"); + * + * Matcher m = p.matcher("Hello, Android!"); + * while (m.find()) { + * System.out.println(m.group()); // prints "Hello" and "Android" + * } + * </pre> + * + * <p/> + * + * The {@code Matcher} has a state that results from the previous operations. + * For example, it knows whether the most recent attempt to find the + * {@code Pattern} was successful and at which position the next attempt would + * resume the search. Depending on the application's needs, it may become + * necessary to explicitly {@link #reset()} this state from time to time. + * + * @since Android 1.0 + */ +public final class Matcher implements MatchResult { + + /** + * Holds the pattern, that is, the compiled regular expression. + */ + private Pattern pattern; + + /** + * Holds the handle for the native version of the pattern. + */ + private int nativePattern; + + /** + * Holds the input text. + */ + private String input = ""; + + /** + * Holds the start of the region, or 0 if the matching should start at the + * beginning of the text. + */ + private int regionStart; + + /** + * Holds the end of the region, or input.length() if the matching should + * go until the end of the input. + */ + private int regionEnd; + + /** + * Reflects whether we just reset the matcher or whether we already + * started some find/replace operations. + */ + private boolean searching; + + /** + * Holds the position where the next find operation will take place. + */ + private int findPos; + + /** + * Holds the position where the next append operation will take place. + */ + private int appendPos; + + /** + * Reflects whether a match has been found during the most recent find + * operation. + */ + private boolean matchFound; + + /** + * Holds the offsets for the most recent match. + */ + private int[] matchOffsets; + + /** + * Reflects whether the bounds of the region are anchoring. + */ + private boolean anchoringBounds = true; + + /** + * Reflects whether the bounds of the region are transparent. + */ + private boolean transparentBounds; + + /** + * Creates a matcher for a given combination of pattern and input. Both + * elements can be changed later on. + * + * @param pattern + * the pattern to use. + * @param input + * the input to use. + */ + Matcher(Pattern pattern, CharSequence input) { + usePattern(pattern); + reset(input); + } + + /** + * Resets the Matcher. A new input sequence and a new region can be + * specified. Results of a previous find get lost. The next attempt to find + * an occurrence of the Pattern in the string will start at the beginning of + * the region. This is the internal version of reset() to which the several + * public versions delegate. + * + * @param input + * the input sequence. + * @param start + * the start of the region. + * @param end + * the end of the region. + * + * @return the matcher itself. + */ + private Matcher reset(CharSequence input, int start, int end) { + if (input == null) { + throw new IllegalArgumentException(); + } + + if (start < 0 || end < 0 || start > input.length() || + end > input.length() || start > end) { + throw new IllegalArgumentException(); + } + + // Maybe should have a reset() here, but it makes thing worse... + // NativeRegEx.reset(nativePattern, 0); + + if (!input.equals(this.input)) { + this.input = input.toString(); + + NativeRegEx.setText(nativePattern, this.input); + + regionStart = 0; + regionEnd = input.length(); + } + + if (start != regionStart || end != regionEnd) { + regionStart = start; + regionEnd = end; + + NativeRegEx.setRegion(nativePattern, regionStart, regionEnd); + } + + searching = false; + matchFound = false; + findPos = regionStart; + appendPos = 0; + + return this; + } + + /** + * Resets the {@code Matcher}. This results in the region being set to the + * whole input. Results of a previous find get lost. The next attempt to + * find an occurrence of the {@link Pattern} in the string will start at the + * beginning of the input. + * + * @return the {@code Matcher} itself. + * + * @since Android 1.0 + */ + public Matcher reset() { + return reset(input, 0, input.length()); + } + + /** + * Provides a new input and resets the {@code Matcher}. This results in the + * region being set to the whole input. Results of a previous find get lost. + * The next attempt to find an occurrence of the {@link Pattern} in the + * string will start at the beginning of the input. + * + * @param input + * the new input sequence. + * + * @return the {@code Matcher} itself. + * + * @since Android 1.0 + */ + public Matcher reset(CharSequence input) { + return reset(input, 0, input.length()); + } + + /** + * Sets a new pattern for the {@code Matcher}. Results of a previous find + * get lost. The next attempt to find an occurrence of the {@link Pattern} + * in the string will start at the beginning of the input. + * + * @param pattern + * the new {@code Pattern}. + * + * @return the {@code Matcher} itself. + * + * @since Android 1.0 + */ + public Matcher usePattern(Pattern pattern) { + if (pattern == null) { + throw new IllegalArgumentException(); + } + + this.pattern = pattern; + + if (nativePattern != 0) { + NativeRegEx.close(nativePattern); + } + nativePattern = NativeRegEx.clone(pattern.mNativePattern); + + if (input != null) { + NativeRegEx.setText(nativePattern, input); + NativeRegEx.setRegion(nativePattern, regionStart, regionEnd); + NativeRegEx.useAnchoringBounds(nativePattern, anchoringBounds); + NativeRegEx.useTransparentBounds(nativePattern, transparentBounds); + } + + matchOffsets = new int[(this.pattern.mGroupCount + 1) * 2]; + matchFound = false; + return this; + } + + /** + * Returns the {@link Pattern} instance used inside this matcher. + * + * @return the {@code Pattern} instance. + * + * @since Android 1.0 + */ + public Pattern pattern() { + return pattern; + } + + /** + * Returns the number of groups in the results, which is always equal to + * the number of groups in the original regular expression. + * + * @return the number of groups. + * + * @since Android 1.0 + */ + public int groupCount() { + return pattern.mGroupCount; + } + + /** + * Resets this matcher and sets a region. Only characters inside the region + * are considered for a match. + * + * @param start + * the first character of the region. + * @param end + * the first character after the end of the region. + * @return the {@code Matcher} itself. + * @since Android 1.0 + */ + public Matcher region(int start, int end) { + return reset(input, start, end); + } + + /** + * Returns this matcher's region start, that is, the first character that is + * considered for a match. + * + * @return the start of the region. + * @since Android 1.0 + */ + public int regionStart() { + return regionStart; + } + + /** + * Returns this matcher's region end, that is, the first character that is + * not considered for a match. + * + * @return the end of the region. + * @since Android 1.0 + */ + public int regionEnd() { + return regionEnd; + } + + /** + * Determines whether this matcher has anchoring bounds enabled or not. When + * anchoring bounds are enabled, the start and end of the input match the + * '^' and '$' meta-characters, otherwise not. Anchoring bounds are enabled + * by default. + * + * @param value + * the new value for anchoring bounds. + * @return the {@code Matcher} itself. + * @since Android 1.0 + */ + public Matcher useAnchoringBounds(boolean value) { + anchoringBounds = value; + NativeRegEx.useAnchoringBounds(nativePattern, value); + return this; + } + + /** + * Indicates whether this matcher has anchoring bounds enabled. When + * anchoring bounds are enabled, the start and end of the input match the + * '^' and '$' meta-characters, otherwise not. Anchoring bounds are enabled + * by default. + * + * @return true if (and only if) the {@code Matcher} uses anchoring bounds. + * @since Android 1.0 + */ + public boolean hasAnchoringBounds() { + return anchoringBounds; + } + + /** + * Determines whether this matcher has transparent bounds enabled or not. + * When transparent bounds are enabled, the parts of the input outside the + * region are subject to lookahead and lookbehind, otherwise they are not. + * Transparent bounds are disabled by default. + * + * @param value + * the new value for transparent bounds. + * @return the {@code Matcher} itself. + * @since Android 1.0 + */ + public Matcher useTransparentBounds(boolean value) { + transparentBounds = value; + NativeRegEx.useTransparentBounds(nativePattern, value); + return this; + } + + /** + * Indicates whether this matcher has transparent bounds enabled. When + * transparent bounds are enabled, the parts of the input outside the region + * are subject to lookahead and lookbehind, otherwise they are not. + * Transparent bounds are disabled by default. + * + * @return true if (and only if) the {@code Matcher} uses anchoring bounds. + * @since Android 1.0 + */ + public boolean hasTransparentBounds() { + return transparentBounds; + } + + /** + * Makes sure that a successful match has been made. Is invoked internally + * from various places in the class. + * + * @throws IllegalStateException + * if no successful match has been made. + * + * @since Android 1.0 + */ + private void ensureMatch() throws IllegalStateException { + if (!matchFound) { + throw new IllegalStateException("No successful match so far"); + } + } + + /** + * Returns the next occurrence of the {@link Pattern} in the input. If a + * previous match was successful, the method continues the search from the + * first character following that match in the input. Otherwise it searches + * either from the region start (if one has been set), or from position 0. + * + * @return true if (and only if) a match has been found. + * @since Android 1.0 + */ + public boolean find() { + if (!searching) { + searching = true; + matchFound = NativeRegEx.find(nativePattern, -1); + } else { + matchFound = NativeRegEx.findNext(nativePattern); + } + + if (matchFound) { + NativeRegEx.startEnd(nativePattern, matchOffsets); + findPos = matchOffsets[1]; + } + + return matchFound; + } + + /** + * Returns the next occurrence of the {@link Pattern} in the input. The + * method starts the search from the given character in the input. + * + * @param start + * The index in the input at which the find operation is to + * begin. If this is less than the start of the region, it is + * automatically adjusted to that value. If it is beyond the end + * of the region, the method will fail. + * @return true if (and only if) a match has been found. + * @since Android 1.0 + */ + public boolean find(int start) { + findPos = start; + + if (findPos < regionStart) { + findPos = regionStart; + } else if (findPos >= regionEnd) { + matchFound = false; + return false; + } + + matchFound = NativeRegEx.find(nativePattern, findPos); + if (matchFound) { + NativeRegEx.startEnd(nativePattern, matchOffsets); + findPos = matchOffsets[1]; + } + + return matchFound; + } + + /** + * Tries to match the {@link Pattern} against the entire region (or the + * entire input, if no region has been set). + * + * @return true if (and only if) the {@code Pattern} matches the entire + * region. + * + * @since Android 1.0 + */ + public boolean matches() { + matchFound = NativeRegEx.matches(nativePattern, -1); + if (matchFound) { + NativeRegEx.startEnd(nativePattern, matchOffsets); + findPos = matchOffsets[1]; + } + + return matchFound; + } + + /** + * Tries to match the {@link Pattern}, starting from the beginning of the + * region (or the beginning of the input, if no region has been set). + * Doesn't require the {@code Pattern} to match against the whole region. + * + * @return true if (and only if) the {@code Pattern} matches. + * + * @since Android 1.0 + */ + public boolean lookingAt() { + matchFound = NativeRegEx.lookingAt(nativePattern, -1); + if (matchFound) { + NativeRegEx.startEnd(nativePattern, matchOffsets); + findPos = matchOffsets[1]; + } + + return matchFound; + } + + /** + * Returns the index of the first character of the text that matched the + * whole regular expression. + * + * @return the character index. + * @throws IllegalStateException + * if no successful match has been made. + * @since Android 1.0 + */ + public int start() throws IllegalStateException { + return start(0); + } + + /** + * Returns the index of the first character of the text that matched a given + * group. + * + * @param group + * the group, ranging from 0 to groupCount() - 1, with 0 + * representing the whole pattern. + * @return the character index. + * @throws IllegalStateException + * if no successful match has been made. + * @since Android 1.0 + */ + public int start(int group) throws IllegalStateException { + ensureMatch(); + return matchOffsets[group * 2]; + } + + /** + * Returns the index of the first character following the text that matched + * the whole regular expression. + * + * @return the character index. + * @throws IllegalStateException + * if no successful match has been made. + * @since Android 1.0 + */ + public int end() { + return end(0); + } + + /** + * Returns the index of the first character following the text that matched + * a given group. + * + * @param group + * the group, ranging from 0 to groupCount() - 1, with 0 + * representing the whole pattern. + * @return the character index. + * @throws IllegalStateException + * if no successful match has been made. + * @since Android 1.0 + */ + public int end(int group) { + ensureMatch(); + return matchOffsets[(group * 2) + 1]; + } + + /** + * Returns the text that matched the whole regular expression. + * + * @return the text. + * @throws IllegalStateException + * if no successful match has been made. + * @since Android 1.0 + */ + public String group() { + return group(0); + } + + /** + * Returns the text that matched a given group of the regular expression. + * + * @param group + * the group, ranging from 0 to groupCount() - 1, with 0 + * representing the whole pattern. + * @return the text that matched the group. + * @throws IllegalStateException + * if no successful match has been made. + * @since Android 1.0 + */ + public String group(int group) { + ensureMatch(); + int from = matchOffsets[group * 2]; + int to = matchOffsets[(group * 2) + 1]; + if (from == -1 || to == -1) { + return null; + } else { + return input.substring(from, to); + } + } + + /** + * Indicates whether the last match hit the end of the input. + * + * @return true if (and only if) the last match hit the end of the input. + * @since Android 1.0 + */ + public boolean hitEnd() { + return NativeRegEx.hitEnd(nativePattern); + } + + /** + * Indicates whether more input might change a successful match into an + * unsuccessful one. + * + * @return true if (and only if) more input might change a successful match + * into an unsuccessful one. + * @since Android 1.0 + */ + public boolean requireEnd() { + return NativeRegEx.requireEnd(nativePattern); + } + + /** + * Converts the current match into a separate {@link MatchResult} instance + * that is independent from this matcher. The new object is unaffected when + * the state of this matcher changes. + * + * @return the new {@code MatchResult}. + * @throws IllegalStateException + * if no successful match has been made. + * @since Android 1.0 + */ + public MatchResult toMatchResult() { + ensureMatch(); + return new MatchResultImpl(input, matchOffsets); + } + + /** + * Appends a literal part of the input plus a replacement for the current + * match to a given {@link StringBuffer}. The literal part is exactly the + * part of the input between the previous match and the current match. The + * method can be used in conjunction with {@link #find()} and + * {@link #appendTail(StringBuffer)} to walk through the input and replace + * all occurrences of the {@code Pattern} with something else. + * + * @param buffer + * the {@code StringBuffer} to append to. + * @param replacement + * the replacement text. + * @return the {@code Matcher} itself. + * @throws IllegalStateException + * if no successful match has been made. + * @since Android 1.0 + */ + public Matcher appendReplacement(StringBuffer buffer, String replacement) + throws IllegalStateException { + + buffer.append(input.substring(appendPos, start())); + appendEvaluated(buffer, replacement); + appendPos = end(); + + return this; + } + + /** + * Appends the (unmatched) remainder of the input to the given + * {@link StringBuffer}. The method can be used in conjunction with + * {@link #find()} and {@link #appendReplacement(StringBuffer, String)} to + * walk through the input and replace all matches of the {@code Pattern} + * with something else. + * + * @param buffer + * the {@code StringBuffer} to append to. + * @return the {@code StringBuffer}. + * @throws IllegalStateException + * if no successful match has been made. + * @since Android 1.0 + */ + public StringBuffer appendTail(StringBuffer buffer) { + if (appendPos < regionEnd) { + buffer.append(input.substring(appendPos, regionEnd)); + } + + return buffer; + } + + /** + * Internal helper method to append a given string to a given string buffer. + * If the string contains any references to groups, these are replaced by + * the corresponding group's contents. + * + * @param buffer + * the string buffer. + * @param s + * the string to append. + */ + private void appendEvaluated(StringBuffer buffer, String s) { + boolean escape = false; + boolean dollar = false; + + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (c == '\\' && !escape) { + escape = true; + } else if (c == '$' && !escape) { + dollar = true; + } else if (c >= '0' && c <= '9' && dollar) { + buffer.append(group(c - '0')); + dollar = false; + } else { + buffer.append(c); + dollar = false; + escape = false; + } + } + + // This seemingly stupid piece of code reproduces a JDK bug. + if (escape) { + throw new ArrayIndexOutOfBoundsException(s.length()); + } + } + + /** + * Replaces all occurrences of this matcher's pattern in the input with a + * given string. + * + * @param replacement + * the replacement text. + * @return the modified input string. + * @since Android 1.0 + */ + public String replaceAll(String replacement) { + StringBuffer buffer = new StringBuffer(input.length()); + + findPos = 0; + appendPos = 0; + matchFound = false; + searching = false; + + while (find()) { + appendReplacement(buffer, replacement); + } + + return appendTail(buffer).toString(); + } + + /** + * Replaces the first occurrence of this matcher's pattern in the input with + * a given string. + * + * @param replacement + * the replacement text. + * @return the modified input string. + * @since Android 1.0 + */ + public String replaceFirst(String replacement) { + StringBuffer buffer = new StringBuffer(input.length()); + + findPos = 0; + appendPos = 0; + matchFound = false; + searching = false; + + if (find()) { + appendReplacement(buffer, replacement); + } + + return appendTail(buffer).toString(); + } + + /** + * Returns a replacement string for the given one that has all backslashes + * and dollar signs escaped. + * + * @param s + * the input string. + * @return the input string, with all backslashes and dollar signs having + * been escaped. + * @since Android 1.0 + */ + public static String quoteReplacement(String s) { + StringBuffer buffer = new StringBuffer(s.length()); + + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (c == '\\' || c == '$') { + buffer.append('\\'); + } + buffer.append(c); + } + + return buffer.toString(); + } + + @Override + protected void finalize() throws Throwable { + try { + if (nativePattern != 0) { + NativeRegEx.close(nativePattern); + } + } + finally { + super.finalize(); + } + } + +} diff --git a/regex/src/main/java/java/util/regex/Pattern.java b/regex/src/main/java/java/util/regex/Pattern.java new file mode 100644 index 0000000..c058db8 --- /dev/null +++ b/regex/src/main/java/java/util/regex/Pattern.java @@ -0,0 +1,479 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * 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. + */ + +package java.util.regex; + +import java.io.Serializable; +import java.util.ArrayList; +import com.ibm.icu4jni.regex.NativeRegEx; + +/** + * Represents a pattern used for matching, searching, or replacing strings. + * {@code Pattern}s are specified in terms of regular expressions and compiled + * using an instance of this class. They are then used in conjunction with a + * {@link Matcher} to perform the actual search. + * <p/> + * A typical use case looks like this: + * <p/> + * <pre> + * Pattern p = Pattern.compile("Hello, A[a-z]*!"); + * + * Matcher m = p.matcher("Hello, Android!"); + * boolean b1 = m.matches(); // true + * + * m.setInput("Hello, Robot!"); + * boolean b2 = m.matches(); // false + * </pre> + * <p/> + * The above code could also be written in a more compact fashion, though this + * variant is less efficient, since {@code Pattern} and {@code Matcher} objects + * are created on the fly instead of being reused. + * fashion: + * <pre> + * boolean b1 = Pattern.matches("Hello, A[a-z]*!", "Hello, Android!"); // true + * boolean b2 = Pattern.matches("Hello, A[a-z]*!", "Hello, Robot!"); // false + * </pre> + * <p/> + * Please consult the <a href="package.html">package documentation</a> for an + * overview of the regular expression syntax used in this class as well as + * Android-specific implementation details. + * + * @see Matcher + * @since Android 1.0 + */ +public final class Pattern implements Serializable { + + private static final long serialVersionUID = 5073258162644648461L; + + /** + * This constant specifies that a pattern matches Unix line endings ('\n') + * only against the '.', '^', and '$' meta characters. + * + * @since Android 1.0 + */ + public static final int UNIX_LINES = 0x01; + + /** + * This constant specifies that a {@code Pattern} is matched + * case-insensitively. That is, the patterns "a+" and "A+" would both match + * the string "aAaAaA". + * <p> + * Note: For Android, the {@code CASE_INSENSITIVE} constant + * (currently) always includes the meaning of the {@link #UNICODE_CASE} + * constant. So if case insensitivity is enabled, this automatically extends + * to all Unicode characters. The {@code UNICODE_CASE} constant itself has + * no special consequences. + * + * @since Android 1.0 + */ + public static final int CASE_INSENSITIVE = 0x02; + + /** + * This constant specifies that a {@code Pattern} may contain whitespace or + * comments. Otherwise comments and whitespace are taken as literal + * characters. + * + * @since Android 1.0 + */ + public static final int COMMENTS = 0x04; + + /** + * This constant specifies that the meta characters '^' and '$' match only + * the beginning and end end of an input line, respectively. Normally, they + * match the beginning and the end of the complete input. + * + * @since Android 1.0 + */ + public static final int MULTILINE = 0x08; + + /** + * This constant specifies that the whole {@code Pattern} is to be taken + * literally, that is, all meta characters lose their meanings. + * + * @since Android 1.0 + */ + public static final int LITERAL = 0x10; + + /** + * This constant specifies that the '.' meta character matches arbitrary + * characters, including line endings, which is normally not the case. + * + * @since Android 1.0 + */ + public static final int DOTALL = 0x20; + + /** + * This constant specifies that a {@code Pattern} is matched + * case-insensitively with regard to all Unicode characters. It is used in + * conjunction with the {@link #CASE_INSENSITIVE} constant to extend its + * meaning to all Unicode characters. + * <p> + * Note: For Android, the {@code CASE_INSENSITIVE} constant + * (currently) always includes the meaning of the {@code UNICODE_CASE} + * constant. So if case insensitivity is enabled, this automatically extends + * to all Unicode characters. The {@code UNICODE_CASE} constant then has no + * special consequences. + * + * @since Android 1.0 + */ + public static final int UNICODE_CASE = 0x40; + + /** + * This constant specifies that a character in a {@code Pattern} and a + * character in the input string only match if they are canonically + * equivalent. It is (currently) not supported in Android. + * + * @since Android 1.0 + */ + public static final int CANON_EQ = 0x80; + + /** + * Holds the regular expression. + */ + private String pattern; + + /** + * Holds the flags used when compiling this pattern. + */ + private int flags; + + /** + * Holds a handle (a pointer, actually) for the native ICU pattern. + */ + transient int mNativePattern; + + /** + * Holds the number of groups in the pattern. + */ + transient int mGroupCount; + + /** + * Compiles a regular expression, creating a new Pattern instance in the + * process. This is actually a convenience method that calls {@link + * #compile(String, int)} with a {@code flags} value of zero. + * + * @param pattern + * the regular expression. + * + * @return the new {@code Pattern} instance. + * + * @throws PatternSyntaxException + * if the regular expression is syntactically incorrect. + * + * @since Android 1.0 + */ + public static Pattern compile(String pattern) throws PatternSyntaxException { + return new Pattern(pattern, 0); + } + + /** + * Compiles a regular expression, creating a new {@code Pattern} instance in + * the process. Allows to set some flags that modify the behavior of the + * {@code Pattern}. + * + * @param pattern + * the regular expression. + * @param flags + * the flags to set. Basically, any combination of the constants + * defined in this class is valid. + * <p> + * Note: Currently, the {@link #CASE_INSENSITIVE} and + * {@link #UNICODE_CASE} constants have slightly special behavior + * in Android, and the {@link #CANON_EQ} constant is not + * supported at all. + * + * @return the new {@code Pattern} instance. + * + * @throws PatternSyntaxException + * if the regular expression is syntactically incorrect. + * + * @see #CANON_EQ + * @see #CASE_INSENSITIVE + * @see #COMMENTS + * @see #DOTALL + * @see #LITERAL + * @see #MULTILINE + * @see #UNICODE_CASE + * @see #UNIX_LINES + * + * @since Android 1.0 + */ + public static Pattern compile(String pattern, int flags) throws PatternSyntaxException { + return new Pattern(pattern, flags); + } + + /** + * Creates a new {@code Pattern} instance from a given regular expression + * and flags. + * + * @param pattern + * the regular expression. + * @param flags + * the flags to set. Any combination of the constants defined in + * this class is valid. + * + * @throws PatternSyntaxException + * if the regular expression is syntactically incorrect. + */ + private Pattern(String pattern, int flags) throws PatternSyntaxException { + if ((flags & CANON_EQ) != 0) { + throw new UnsupportedOperationException("CANON_EQ flag not supported"); + } + + this.pattern = pattern; + this.flags = flags; + + compileImpl(pattern, flags); + } + + /** + * Compiles the given regular expression using the given flags. Used + * internally only. + * + * @param pattern + * the regular expression. + * @param flags + * the flags. + */ + private void compileImpl(String pattern, int flags) throws PatternSyntaxException { + if (pattern == null) { + throw new NullPointerException(); + } + + if ((flags & LITERAL) != 0) { + pattern = quote(pattern); + } + + // These are the flags natively supported by ICU. + // They even have the same value in native code. + flags = flags & (CASE_INSENSITIVE | COMMENTS | MULTILINE | DOTALL | UNIX_LINES); + + mNativePattern = NativeRegEx.open(pattern, flags); + mGroupCount = NativeRegEx.groupCount(mNativePattern); + } + + /** + * Returns the regular expression that was compiled into this + * {@code Pattern}. + * + * @return the regular expression. + * + * @since Android 1.0 + */ + public String pattern() { + return pattern; + } + + /** + * Returns the flags that have been set for this {@code Pattern}. + * + * @return the flags that have been set. A combination of the constants + * defined in this class. + * + * @see #CANON_EQ + * @see #CASE_INSENSITIVE + * @see #COMMENTS + * @see #DOTALL + * @see #LITERAL + * @see #MULTILINE + * @see #UNICODE_CASE + * @see #UNIX_LINES + * + * @since Android 1.0 + */ + public int flags() { + return flags; + } + + /** + * Returns a {@link Matcher} for the {@code Pattern} and a given input. The + * {@code Matcher} can be used to match the {@code Pattern} against the + * whole input, find occurrences of the {@code Pattern} in the input, or + * replace parts of the input. + * + * @param input + * the input to process. + * + * @return the resulting {@code Matcher}. + * + * @since Android 1.0 + */ + public Matcher matcher(CharSequence input) { + return new Matcher(this, input); + } + + /** + * Tries to match a given regular expression against a given input. This is + * actually nothing but a convenience method that compiles the regular + * expression into a {@code Pattern}, builds a {@link Matcher} for it, and + * then does the match. If the same regular expression is used for multiple + * operations, it is recommended to compile it into a {@code Pattern} + * explicitly and request a reusable {@code Matcher}. + * + * @param regex + * the regular expression. + * @param input + * the input to process. + * + * @return true if and only if the {@code Pattern} matches the input. + * + * @see Pattern#compile(java.lang.String, int) + * @see Matcher#matches() + * + * @since Android 1.0 + */ + static public boolean matches(String regex, CharSequence input) { + return new Matcher(new Pattern(regex, 0), input).matches(); + } + + /** + * Splits a given input around occurrences of a regular expression. This is + * a convenience method that is equivalent to calling the method + * {@link #split(java.lang.CharSequence, int)} with a limit of 0. + * + * @param input + * the input sequence. + * + * @return the resulting array. + * + * @since Android 1.0 + */ + public String[] split(CharSequence input) { + return split(input, 0); + } + + /** + * Splits the given input sequence around occurrences of the {@code Pattern}. + * The function first determines all occurrences of the {@code Pattern} + * inside the input sequence. It then builds an array of the + * "remaining" strings before, in-between, and after these + * occurrences. An additional parameter determines the maximal number of + * entries in the resulting array and the handling of trailing empty + * strings. + * + * @param inputSeq + * the input sequence. + * @param limit + * Determines the maximal number of entries in the resulting + * array. + * <ul> + * <li>For n > 0, it is guaranteed that the resulting array + * contains at most n entries. + * <li>For n < 0, the length of the resulting array is + * exactly the number of occurrences of the {@code Pattern} +1. + * All entries are included. + * <li>For n == 0, the length of the resulting array is at most + * the number of occurrences of the {@code Pattern} +1. Empty + * strings at the end of the array are not included. + * </ul> + * + * @return the resulting array. + * + * @since Android 1.0 + */ + public String[] split(CharSequence inputSeq, int limit) { + int maxLength = limit <= 0 ? Integer.MAX_VALUE : limit; + + String input = inputSeq.toString(); + ArrayList<String> list = new ArrayList<String>(); + + Matcher matcher = new Matcher(this, inputSeq); + int savedPos = 0; + + // Add text preceding each occurrence, if enough space. Only do this for + // non-empty input sequences, because otherwise we'd add the "trailing + // empty string" twice. + if (inputSeq.length() != 0) { + while(matcher.find() && list.size() + 1 < maxLength) { + list.add(input.substring(savedPos, matcher.start())); + savedPos = matcher.end(); + } + } + + // Add trailing text if enough space. + if (list.size() < maxLength) { + if (savedPos < input.length()) { + list.add(input.substring(savedPos)); + } else { + list.add(""); + } + } + + // Remove trailing spaces, if limit == 0 is requested. + if (limit == 0) { + int i = list.size() - 1; + // Don't remove 1st element, since array must not be empty. + while(i > 0 && "".equals(list.get(i))) { + list.remove(i); + i--; + } + } + + return list.toArray(new String[list.size()]); + } + + /** + * Quotes a given string using "\Q" and "\E", so that all other + * meta-characters lose their special meaning. If the string is used for a + * {@code Pattern} afterwards, it can only be matched literally. + * + * @param s + * the string to quote. + * + * @return the quoted string. + * + * @since Android 1.0 + */ + public static String quote(String s) { + StringBuffer sb = new StringBuffer().append("\\Q"); + int apos = 0; + int k; + while ((k = s.indexOf("\\E", apos)) >= 0) { + sb.append(s.substring(apos, k + 2)).append("\\\\E\\Q"); + apos = k + 2; + } + + return sb.append(s.substring(apos)).append("\\E").toString(); + } + + @Override + public String toString() { + return pattern; + } + + @Override + protected void finalize() throws Throwable { + try { + if (mNativePattern != 0) { + NativeRegEx.close(mNativePattern); + } + } + finally { + super.finalize(); + } + } + + /** + * Provides serialization support + */ + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { + s.defaultReadObject(); + + compileImpl(pattern, flags); + } + +} diff --git a/regex/src/main/java/java/util/regex/PatternSyntaxException.java b/regex/src/main/java/java/util/regex/PatternSyntaxException.java new file mode 100644 index 0000000..e4d5abd --- /dev/null +++ b/regex/src/main/java/java/util/regex/PatternSyntaxException.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * 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. + */ + +package java.util.regex; + +import java.util.Arrays; + +/** + * Encapsulates a syntax error that occurred during the compilation of a + * {@link Pattern}. Might include a detailed description, the original regular + * expression, and the index at which the error occurred. + * + * @see Pattern#compile(String) + * @see Pattern#compile(java.lang.String,int) + * + * @since Android 1.0 + */ +public class PatternSyntaxException extends IllegalArgumentException { + + private static final long serialVersionUID = -3864639126226059218L; + + /** + * Holds the syntactically incorrect regular expression, or null if the + * regular expression is not known. + */ + private String pattern; + + /** + * Holds the description of the syntax error, or null if the description is + * not known. + */ + private String description; + + /** + * Holds the index around which the error occured, or -1, in case it is + * unknown. + */ + private int index = -1; + + /** + * Creates a new PatternSyntaxException for a given message, pattern, and + * error index. + * + * @param description + * the description of the syntax error, or {@code null} if the + * description is not known. + * @param pattern + * the syntactically incorrect regular expression, or + * {@code null} if the regular expression is not known. + * @param index + * the character index around which the error occurred, or -1 if + * the index is not known. + * @since Android 1.0 + */ + public PatternSyntaxException(String description, String pattern, int index) { + this.pattern = pattern; + this.description = description; + this.index = index; + } + + /** + * Returns the syntactically incorrect regular expression. + * + * @return the regular expression. + * + * @since Android 1.0 + */ + public String getPattern() { + return pattern; + } + + /** + * Returns a detailed error message for the exception. The message is + * potentially multi-line, and it might include a detailed description, the + * original regular expression, and the index at which the error occured. + * + * @return the error message. + * + * @since Android 1.0 + */ + @Override + public String getMessage() { + StringBuilder builder = new StringBuilder("Syntax error"); + + if (description != null) { + builder.append(' '); + builder.append(description); + } + + if (index >= 0) { + builder.append(" near index " + index + ":"); + } + + if (pattern != null) { + builder.append('\n'); + builder.append(pattern); + + if (index >= 0) { + char[] spaces = new char[index]; + Arrays.fill(spaces, ' '); + builder.append('\n'); + builder.append(spaces); + builder.append('^'); + } + } + + return builder.toString(); + } + + /** + * Returns the description of the syntax error, or {@code null} if the + * description is not known. + * + * @return the description. + * @since Android 1.0 + */ + public String getDescription() { + return description; + } + + /** + * Returns the character index around which the error occurred, or -1 if the + * index is not known. + * + * @return the index. + * + * @since Android 1.0 + */ + public int getIndex() { + return index; + } + +} diff --git a/regex/src/main/java/java/util/regex/package.html b/regex/src/main/java/java/util/regex/package.html new file mode 100644 index 0000000..0508f3e --- /dev/null +++ b/regex/src/main/java/java/util/regex/package.html @@ -0,0 +1,884 @@ +<html> + <head> + <!-- + /* + * Copyright (C) 2007 The Android Open Source Project + * + * 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. + */ + --> + </head> + <body> + Provides an implementation of regular expressions, which is useful for + matching, searching, and replacing strings based on patterns. The two + fundamental classes are {@link java.util.regex.Pattern} and + {@link java.util.regex.Matcher}. The former + takes a pattern described by means of a regular expression and compiles it + into a special internal representation. The latter matches the compiled + pattern against a given input. + + <h2>Regular expressions</h2> + + A regular expression consists of literal text, meta characters, character + sets, and operators. The latter three have a special meaning when + encountered during the processing of a pattern. + + <ul> + <li> + <a href="#metachars">Meta characters</a> are a special means to describe + single characters in the input text. A common example for a meta + character is the dot '.', which, when used in a regular expression, + matches any character. + </li> + <li> + <a href="#charsets">Character sets</a> are a convenient means to + describe different characters that match a single character in the + input. Character sets are enclosed in angular brackets '[' and ']' + and use the dash '-' for forming ranges. A typical example is + "[0-9a-fA-F]", which describes the set of all hexadecimal digits. + </li> + <li> + <a href="#operators">Operators</a> modify or combine whole regular + expressions, with the result being a regular expression again. An + example for an operator is the asterisk '*', which, together with the + regular expression preceding it, matches zero or more repetitions of + that regular expression. The plus sign '+' is similar, but requires at + least one occurrence. + </li> + </ul> + + Meta characters, the '[' and ']' that form a character set, and operators + normally lose their special meaning when preceded by a backslash '\'. To get + a backslash by itself, use a double backslash. Note that when using regular + expressions in Java source code, some care has to be taken to get the + backslashes right (due to yet another level of escaping being necessary for + Java). + + <p> + + The following table gives some basic examples of regular expressions and + input strings that match them: + + <p> + + <table> + <tr> + <th> + Regular expression + </th> + <th> + Matched string(s) + </th> + </tr> + <tr> + <td> + "Hello, World!" + </td> + <td> + "Hello, World!" + </td> + </tr> + <tr> + <td> + "Hello, World." + </td> + <td> + "Hello, World!", "Hello, World?" + </td> + </tr> + <tr> + <td> + "Hello, .*d!" + </td> + <td> + "Hello, World!", "Hello, Android!", "Hello, Dad!" + </td> + </tr> + <tr> + <td> + "[0-9]+ green bottles" + </td> + <td> + "0 green bottles", "25 green bottles", "1234 green bottles" + </td> + </tr> + </table> + + <p> + + The following section describe the various features in detail. The are also + some <a href="#impnotes">implementation notes</a> at the end. + + <p> + + <a name="metachars"></a> + <h2>Meta characters</h2> + + The following two tables lists the meta characters understood in regular + expressions. + + <p> + + <!-- ICU-copied documentation begins here --> + + <table> + <tr> + <th> + Meta character + </th> + <th> + Description + </th> + </tr> + <tr> + <td> + \a + </td> + <td> + Match a BELL, \u0007. + </td> + </tr> + <tr> + <td> + \A + </td> + <td> + Match at the beginning of the input. Differs from ^ in that + \A will not match after a new line within the input. + </td> + </tr> + <tr> + <td> + \b, outside of a <a href="#charsets">character set</a> + </td> + <td> + Match if the current position is a word boundary. Boundaries + occur at the transitions between word (\w) and non-word (\W) + characters, with combining marks ignored. + </td> + </tr> + <tr> + <td> + \b, within a <a href="#charsets">character set</a> + </td> + <td> + Match a BACKSPACE, \u0008. + </td> + </tr> + <tr> + <td> + \B + </td> + <td> + Match if the current position is not a word boundary. + </td> + </tr> + <tr> + <td> + \cX + </td> + <td> + Match a control-X character (replace X with actual character). + </td> + </tr> + <tr> + <td> + \e + </td> + <td> + Match an ESCAPE, \u001B. + </td> + </tr> + <tr> + <td> + \E + </td> + <td> + Ends quoting started by \Q. Meta characters, character classes, and + operators become active again. + </td> + </tr> + <tr> + <td> + \f + </td> + <td> + Match a FORM FEED, \u000C. + </td> + </tr> + <tr> + <td> + \G + </td> + <td> + Match if the current position is at the end of the previous + match. + </td> + </tr> + <tr> + <td> + \n + </td> + <td> + Match a LINE FEED, \u000A. + </td> + </tr> + <tr> + <td> + \N{UNICODE CHARACTER NAME} + </td> + <td> + Match the named Unicode character. + </td> + </tr> + <tr> + <td> + \Q + </td> + <td> + Quotes all following characters until \E. The following text is + treated as literal. + </td> + </tr> + <tr> + <td> + \r + </td> + <td> + Match a CARRIAGE RETURN, \u000D. + </td> + </tr> + <tr> + <td> + \t + </td> + <td> + Match a HORIZONTAL TABULATION, \u0009. + </td> + </tr> + <tr> + <td> + \uhhhh + </td> + <td> + Match the character with the hex value hhhh. + </td> + </tr> + <tr> + <td> + \Uhhhhhhhh + </td> + <td> + Match the character with the hex value hhhhhhhh. Exactly + eight hex digits must be provided, even though the largest Unicode + code point is \U0010ffff. + </td> + </tr> + <tr> + <td> + \x{hhhh} + </td> + <td> + Match the character with the hex value hhhh. From one to six hex + digits may be supplied. + </td> + </tr> + <tr> + <td> + \xhh + </td> + <td> + Match the character with the hex value hh. + </td> + </tr> + <tr> + <td> + \Z + </td> + <td> + Match if the current position is at the end of input, but + before the final line terminator, if one exists. + </td> + </tr> + <tr> + <td> + \z + </td> + <td> + Match if the current position is at the end of input. + </td> + </tr> + <tr> + <td> + \0n, \0nn, \0nnn + </td> + <td> + Match the character with the octal value n, nn, or nnn. Maximum + value is 0377. + </td> + </tr> + <tr> + <td> + \n + </td> + <td> + Back Reference. Match whatever the nth capturing group + matched. n must be a number > 1 and < total number of capture + groups in the pattern. Note: Octal escapes, such as \012, are not + supported in ICU regular expressions + </td> + </tr> + <tr> + <td> + [character set] + </td> + <td> + Match any one character from the character set. See + <a href="#charsets">character sets</a> for a full description of what + may appear between the angular brackets. + </td> + </tr> + <tr> + <td> + . + </td> + <td> + Match any character. + </td> + </tr> + <tr> + <td> + ^ + </td> + <td> + Match at the beginning of a line. + </td> + </tr> + <tr> + <td> + $ + </td> + <td> + Match at the end of a line. + </td> + </tr> + <tr> + <td> + \ + </td> + <td> + Quotes the following character, so that is loses any special + meaning it might have. + </td> + </tr> + </table> + + <!-- ICU-copied documentation begins here --> + + <p> + + <a name="charsets"></a> + <h2>Character sets</h2> + + The following table lists the syntax elements allowed inside a character + set: + + <p> + + <table> + <tr> + <th> + Element + </th> + <th> + Description + </th> + </tr> + <tr> + <td> + [a] + </td> + <td> + The character set consisting of the letter 'a' only. + </td> + </tr> + <tr> + <td> + [xyz] + </td> + <td> + The character set consisting of the letters 'x', 'y', and 'z', + described by explicit enumeration. + </td> + </tr> + <tr> + <td> + [x-z] + </td> + <td> + The character set consisting of the letters 'x', 'y', and 'z', + described by means of a range. + </td> + </tr> + <tr> + <td> + [^xyz] + </td> + <td> + The character set consisting of everything but the letters 'x', 'y', + and 'z'. + </td> + </tr> + <tr> + <td> + [[a-f][0-9]] + </td> + <td> + The character set formed by building the union of the two character + sets [a-f] and [0-9]. + </td> + </tr> + <tr> + <td> + [[a-z]&&[jkl]] + </td> + <td> + The character set formed by building the intersection of the two + character sets [a-z] and [jkl]. You can also use a single '&', but + this regular expression might not be <a href="#impnotes">portable</a>. + </td> + </tr> + <tr> + <td> + [[a-z]--[jkl]] + </td> + <td> + The character set formed by building the difference of the two + character sets [a-z] and [jkl]. You can also use a single '-'. This + operator is generally not <a href="#impnotes">portable</a>. + </td> + </tr> + </table> + + <p> + + A couple of frequently used character sets are predefined and named. + These can be referenced by their name, but behave otherwise similar to + explicit character sets. The following table lists them: + + <p> + + <table> + <tr> + <th> + Character set + </th> + <th> + Description + </th> + </tr> + <tr> + <td> + \d, \D + </td> + <td> + The set consisting of all digit characters (\d) or the opposite of + it (\D). + </td> + </tr> + <tr> + <td> + \s, \S + </td> + <td> + The set consisting of all space characters (\s) or the opposite of + it (\S). + </td> + </tr> + <tr> + <td> + \w, \W + </td> + <td> + The set consisting of all word characters (\w) or the opposite + of it (\W). + </td> + </tr> + <tr> + <td> + \X + </td> + <td> + The set of all grapheme clusters. + </td> + </tr> + <tr> + <td> + \p{NAME}, \P{NAME} + </td> + <td> + The Posix set with the specified NAME (\p{}) or the opposite + of it (\P{}) - Legal values for NAME are 'Alnum', 'Alpha', 'ASCII', + 'Blank', 'Cntrl', 'Digit', 'Graph', 'Lower', 'Print', 'Punct', + 'Upper', 'XDigit' . + </td> + </tr> + <tr> + <td> + \p{inBLOCK}, \P{inBLOCK} + </td> + <td> + The character set equivalent to the given Unicode BLOCK (\p{}) or + the opposite of it (\P{}). An example for a legal BLOCK name is + 'Hebrew', meaning, unsurprisingly, all Hebrew characters. + </td> + </tr> + <tr> + <td> + \p{CATEGORY}, \P{CATEGORY} + </td> + <td> + The character set equivalent to the Unicode CATEGORY (\p{}) or the + opposite of it (\P{}). An example for a legal CATEGORY name is 'Lu', + meaning all uppercase letters. + </td> + </tr> + <tr> + <td> + \p{javaMETHOD}, \P{javaMETHOD} + </td> + <td> + The character set equivalent to the isMETHOD() operation of the + {@link java.lang.Character} class (\p{}) or the opposite of it (\P{}). + </td> + </tr> + </table> + + <p> + + <a name="operators"></a> + <h2>Operators</h2> + + The following table lists the operators understood inside regular + expressions: + + <p> + + <!-- ICU-copied documentation begins here --> + + <table> + <tr> + <th> + Operator + </th> + <th> + Description + </th> + </tr> + <tr> + <td> + | + </td> + <td> + Alternation. A|B matches either A or B. + </td> + </tr> + <tr> + <td> + * + </td> + <td> + Match 0 or more times. Match as many times as possible. + </td> + </tr> + <tr> + <td> + + + </td> + <td> + Match 1 or more times. Match as many times as possible. + </td> + </tr> + <tr> + <td> + ? + </td> + <td> + Match zero or one times. Prefer one. + </td> + </tr> + <tr> + <td> + {n} + </td> + <td> + Match exactly n times + </td> + </tr> + <tr> + <td> + {n,} + </td> + <td> + Match at least n times. Match as many times as possible. + </td> + </tr> + <tr> + <td> + {n,m} + </td> + <td> + Match between n and m times. Match as many times as possible, + but not more than m. + </td> + </tr> + <tr> + <td> + *? + </td> + <td> + Match 0 or more times. Match as few times as possible. + </td> + </tr> + <tr> + <td> + +? + </td> + <td> + Match 1 or more times. Match as few times as possible. + </td> + </tr> + <tr> + <td> + ?? + </td> + <td> + Match zero or one times. Prefer zero. + </td> + </tr> + <tr> + <td> + {n}? + </td> + <td> + Match exactly n times. + </td> + </tr> + <tr> + <td> + {n,}? + </td> + <td> + Match at least n times, but no more than required for an + overall pattern match + </td> + </tr> + <tr> + <td> + {n,m}? + </td> + <td> + Match between n and m times. Match as few times as possible, + but not less than n. + </td> + </tr> + <tr> + <td> + *+ + </td> + <td> + Match 0 or more times. Match as many times as possible when + first encountered, do not retry with fewer even if overall match + fails (Possessive Match) + </td> + </tr> + <tr> + <td> + ++ + </td> + <td> + Match 1 or more times. Possessive match. + </td> + </tr> + <tr> + <td> + ?+ + </td> + <td> + Match zero or one times. Possessive match. + </td> + </tr> + <tr> + <td> + {n}+ + </td> + <td> + Match exactly n times. + </td> + </tr> + <tr> + <td> + {n,}+ + </td> + <td> + Match at least n times. Possessive Match. + </td> + </tr> + <tr> + <td> + {n,m}+ + </td> + <td> + Match between n and m times. Possessive Match. + </td> + </tr> + <tr> + <td> + ( ... ) + </td> + <td> + Capturing parentheses. Range of input that matched the + parenthesized subexpression is available after the match. + </td> + </tr> + <tr> + <td> + (?: ... ) + </td> + <td> + Non-capturing parentheses. Groups the included pattern, but + does not provide capturing of matching text. Somewhat more efficient + than capturing parentheses. + </td> + </tr> + <tr> + <td> + (?> ... ) + </td> + <td> + Atomic-match parentheses. First match of the parenthesized + subexpression is the only one tried; if it does not lead to an + overall pattern match, back up the search for a match to a position + before the "(?>" + </td> + </tr> + <tr> + <td> + (?# ... ) + </td> + <td> + Free-format comment (?# comment ). + </td> + </tr> + <tr> + <td> + (?= ... ) + </td> + <td> + Look-ahead assertion. True if the parenthesized pattern + matches at the current input position, but does not advance the + input position. + </td> + </tr> + <tr> + <td> + (?! ... ) + </td> + <td> + Negative look-ahead assertion. True if the parenthesized + pattern does not match at the current input position. Does not + advance the input position. + </td> + </tr> + <tr> + <td> + (?<= ... ) + </td> + <td> + Look-behind assertion. True if the parenthesized pattern + matches text preceding the current input position, with the last + character of the match being the input character just before the + current position. Does not alter the input position. The length of + possible strings matched by the look-behind pattern must not be + unbounded (no * or + operators.) + </td> + </tr> + <tr> + <td> + (?<! ... ) + </td> + <td> + Negative Look-behind assertion. True if the parenthesized + pattern does not match text preceding the current input position, + with the last character of the match being the input character just + before the current position. Does not alter the input position. The + length of possible strings matched by the look-behind pattern must + not be unbounded (no * or + operators.) + </td> + </tr> + <tr> + <td> + (?ismwx-ismwx: ... ) + </td> + <td> + Flag settings. Evaluate the parenthesized expression with the + specified flags enabled or -disabled. + </td> + </tr> + <tr> + <td> + (?ismwx-ismwx) + </td> + <td> + Flag settings. Change the flag settings. Changes apply to the + portion of the pattern following the setting. For example, (?i) + changes to a case insensitive match. + </td> + </tr> + </table> + + <!-- ICU-copied documentation ends here --> + + <p> + + <a name="impnotes"></a> + <h2>Implementation notes</h2> + + The regular expression implementation used in Android is provided by + <a href="http://www.icu-project.org">ICU</a>. The notation for the regular + expressions is mostly a superset of those used in other Java language + implementations. This means that existing applications will normally work as + expected, but in rare cases some regular expression content that is meant to + be literal might be interpreted with a special meaning. The most notable + examples are the single '&', which can also be used as the intersection + operator for <a href="#charsets">character sets</a>, and the intersection + operators '-' and '--'. Also, some of the flags are handled in a + slightly different way: + + <ul> + <li> + The {@link java.util.regex.Pattern#CASE_INSENSITIVE} flag silently + assumes Unicode case-insensitivity. That is, the + {@link java.util.regex.Pattern#UNICODE_CASE} flag is effectively a + no-op. + </li> + <li> + The {@link java.util.regex.Pattern#CANON_EQ} flag is not supported at + all (throws an exception). + </li> + </ul> + + @since Android 1.0 + + </body> +</html> diff --git a/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/AllTests.java b/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/AllTests.java new file mode 100644 index 0000000..b69c401 --- /dev/null +++ b/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/AllTests.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.harmony.regex.tests.java.util.regex; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * Provides a test suite for java.util.regex package. + */ +public class AllTests { + + public static void main(String[] args) { + junit.textui.TestRunner.run(suite()); + } + + public static Test suite() { + TestSuite suite = tests.TestSuiteFactory.createTestSuite("Tests for java.util.regex"); + //$JUnit-BEGIN$ + + suite.addTestSuite(Matcher2Test.class); + suite.addTestSuite(MatcherTest.class); + suite.addTestSuite(ModeTest.class); + suite.addTestSuite(Pattern2Test.class); + suite.addTestSuite(PatternErrorTest.class); + suite.addTestSuite(PatternSyntaxExceptionTest.class); + suite.addTestSuite(PatternTest.class); + suite.addTestSuite(ReplaceTest.class); + suite.addTestSuite(SplitTest.class); + + //$JUnit-END$ + return suite; + } +} diff --git a/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/Matcher2Test.java b/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/Matcher2Test.java new file mode 100644 index 0000000..ab0de63 --- /dev/null +++ b/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/Matcher2Test.java @@ -0,0 +1,327 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.harmony.regex.tests.java.util.regex; + +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestLevel; + +import junit.framework.TestCase; +import java.util.regex.*; + +/** + * Tests Matcher methods + * + */ +@TestTargetClass(java.util.regex.Matcher.class) +public class Matcher2Test extends TestCase { + + @TestTargetNew( + level = TestLevel.PARTIAL, + notes = "Verifies the basic functionality of toString() method.", + method = "toString", + args = {} + ) + public void test_toString() { + Pattern p = Pattern.compile("foo"); + Matcher m = p.matcher("bar"); + assertNotNull(m.toString()); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies start, end, group, usePattern methods with wrong conditions, IllegalStateException should be thrown", + method = "start", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies start, end, group, usePattern methods with wrong conditions, IllegalStateException should be thrown", + method = "end", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies start, end, group, usePattern methods with wrong conditions, IllegalStateException should be thrown", + method = "group", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies start, end, group, usePattern methods with wrong conditions, IllegalStateException should be thrown", + method = "start", + args = {int.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies start, end, group, usePattern methods with wrong conditions, IllegalStateException should be thrown", + method = "end", + args = {int.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies start, end, group, usePattern methods with wrong conditions, IllegalStateException should be thrown", + method = "group", + args = {int.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies start, end, group, usePattern methods with wrong conditions, IllegalStateException should be thrown", + method = "usePattern", + args = {java.util.regex.Pattern.class} + ) + }) + public void testErrorConditions() throws PatternSyntaxException { + // Test match cursors in absence of a match + Pattern p = Pattern.compile("foo"); + Matcher m = p.matcher("bar"); + assertFalse(m.matches()); + + try { + m.start(); + fail("IllegalStateException expected"); + } catch (IllegalStateException e) { + } + + try { + m.end(); + fail("IllegalStateException expected"); + } catch (IllegalStateException e) { + } + + try { + m.group(); + fail("IllegalStateException expected"); + } catch (IllegalStateException e) { + } + + try { + m.start(1); + fail("IllegalStateException expected"); + } catch (IllegalStateException e) { + } + + try { + m.end(1); + fail("IllegalStateException expected"); + } catch (IllegalStateException e) { + } + + try { + m.group(1); + fail("IllegalStateException expected"); + } catch (IllegalStateException e) { + } + + // regression test for HARMONY-2418 + try { + m.usePattern(null); + fail("IllegalArgumentException expected"); + } catch (IllegalArgumentException e) { + // PASSED + } + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies end, start, group methods with wrong conditions, IndexOutOfBoundsException, IllegalStateException should be thrown", + method = "start", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies end, start, group methods with wrong conditions, IndexOutOfBoundsException, IllegalStateException should be thrown", + method = "end", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies end, start, group methods with wrong conditions, IndexOutOfBoundsException, IllegalStateException should be thrown", + method = "start", + args = {int.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies end, start, group methods with wrong conditions, IndexOutOfBoundsException, IllegalStateException should be thrown", + method = "end", + args = {int.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies end, start, group methods with wrong conditions, IndexOutOfBoundsException, IllegalStateException should be thrown", + method = "group", + args = {int.class} + ) + }) + public void testErrorConditions2() throws PatternSyntaxException { + // Test match cursors in absence of a match + Pattern p = Pattern.compile("(foo[0-9])(bar[a-z])"); + Matcher m = p.matcher("foo1barzfoo2baryfoozbar5"); + + assertTrue(m.find()); + assertEquals(0, m.start()); + assertEquals(8, m.end()); + assertEquals(0, m.start(1)); + assertEquals(4, m.end(1)); + assertEquals(4, m.start(2)); + assertEquals(8, m.end(2)); + + try { + m.start(3); + fail("IndexOutOfBoundsException expected"); + } catch (IndexOutOfBoundsException e) { + } + + try { + m.end(3); + fail("IndexOutOfBoundsException expected"); + } catch (IndexOutOfBoundsException e) { + } + + try { + m.group(3); + fail("IndexOutOfBoundsException expected"); + } catch (IndexOutOfBoundsException e) { + } + + try { + m.start(-1); + fail("IndexOutOfBoundsException expected"); + } catch (IndexOutOfBoundsException e) { + } + + try { + m.end(-1); + fail("IndexOutOfBoundsException expected"); + } catch (IndexOutOfBoundsException e) { + } + + try { + m.group(-1); + fail("IndexOutOfBoundsException expected"); + } catch (IndexOutOfBoundsException e) { + } + + assertTrue(m.find()); + assertEquals(8, m.start()); + assertEquals(16, m.end()); + assertEquals(8, m.start(1)); + assertEquals(12, m.end(1)); + assertEquals(12, m.start(2)); + assertEquals(16, m.end(2)); + + try { + m.start(3); + fail("IndexOutOfBoundsException expected"); + } catch (IndexOutOfBoundsException e) { + } + + try { + m.end(3); + fail("IndexOutOfBoundsException expected"); + } catch (IndexOutOfBoundsException e) { + } + + try { + m.group(3); + fail("IndexOutOfBoundsException expected"); + } catch (IndexOutOfBoundsException e) { + } + + try { + m.start(-1); + fail("IndexOutOfBoundsException expected"); + } catch (IndexOutOfBoundsException e) { + } + + try { + m.end(-1); + fail("IndexOutOfBoundsException expected"); + } catch (IndexOutOfBoundsException e) { + } + + try { + m.group(-1); + fail("IndexOutOfBoundsException expected"); + } catch (IndexOutOfBoundsException e) { + } + + assertFalse(m.find()); + + try { + m.start(3); + fail("IllegalStateException expected"); + } catch (IllegalStateException e) { + } + + try { + m.end(3); + fail("IllegalStateException expected"); + } catch (IllegalStateException e) { + } + + try { + m.group(3); + fail("IllegalStateException expected"); + } catch (IllegalStateException e) { + } + + try { + m.start(-1); + fail("IllegalStateException expected"); + } catch (IllegalStateException e) { + } + + try { + m.end(-1); + fail("IllegalStateException expected"); + } catch (IllegalStateException e) { + } + + try { + m.group(-1); + fail("IllegalStateException expected"); + } catch (IllegalStateException e) { + } + } + + /* + * Regression test for HARMONY-997 + */ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies that IndexOutOfBoundsException exception is thrown while calling of replaceAll method with incorrect string.", + method = "replaceAll", + args = {java.lang.String.class} + ) + public void testReplacementBackSlash() { + String str = "replace me"; + String replacedString = "me"; + String substitutionString = "\\"; + Pattern pat = Pattern.compile(replacedString); + Matcher mat = pat.matcher(str); + try { + String res = mat.replaceAll(substitutionString); + fail("IndexOutOfBoundsException should be thrown - " + res); + } catch (Exception e) { + } + } +} + diff --git a/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/MatcherTest.java b/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/MatcherTest.java new file mode 100644 index 0000000..5e9137b --- /dev/null +++ b/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/MatcherTest.java @@ -0,0 +1,1471 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.harmony.regex.tests.java.util.regex; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import junit.framework.TestCase; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargets; + +@TestTargetClass( + value = Matcher.class, + untestedMethods= { + @TestTargetNew( + level = TestLevel.NOT_FEASIBLE, + notes = "finalize is hard to test since the implementation only calls a native function", + method = "finalize", + args = {} + ) + } + +) +public class MatcherTest extends TestCase { + String[] testPatterns = { + "(a|b)*abb", + "(1*2*3*4*)*567", + "(a|b|c|d)*aab", + "(1|2|3|4|5|6|7|8|9|0)(1|2|3|4|5|6|7|8|9|0)*", + "(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ)*", + "(a|b)*(a|b)*A(a|b)*lice.*", + "(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)(a|b|c|d|e|f|g|h|" + + "i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)*(1|2|3|4|5|6|7|8|9|0)*|while|for|struct|if|do" }; + + String[] groupPatterns = { "(a|b)*aabb", "((a)|b)*aabb", "((a|b)*)a(abb)", + "(((a)|(b))*)aabb", "(((a)|(b))*)aa(b)b", "(((a)|(b))*)a(a(b)b)" }; + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "", + method = "appendReplacement", + args = {java.lang.StringBuffer.class, java.lang.String.class} + ) + public void testAppendReplacement() { + Pattern pat = Pattern.compile("XX"); + Matcher m = pat.matcher("Today is XX-XX-XX ..."); + StringBuffer sb = new StringBuffer(); + + for (int i = 0; m.find(); i++) { + m.appendReplacement(sb, new Integer(i * 10 + i).toString()); + } + m.appendTail(sb); + assertEquals("Today is 0-11-22 ...", sb.toString()); + + pat = Pattern.compile("cat"); + m = pat.matcher("one-cat-two-cats-in-the-yard"); + sb = new StringBuffer(); + Throwable t = null; + m.find(); + try { + m.appendReplacement(null, "dog"); + } catch (NullPointerException e) { + t = e; + } + assertNotNull(t); + t = null; + m.find(); + try { + m.appendReplacement(sb, null); + } catch (NullPointerException e) { + t = e; + } + assertNotNull(t); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "", + method = "appendReplacement", + args = {java.lang.StringBuffer.class, java.lang.String.class} + ) + public void testAppendReplacementRef() { + Pattern p = Pattern.compile("xx (rur|\\$)"); + Matcher m = p.matcher("xx $ equals to xx rur."); + StringBuffer sb = new StringBuffer(); + for (int i = 1; m.find(); i *= 30) { + String rep = new Integer(i).toString() + " $1"; + m.appendReplacement(sb, rep); + } + m.appendTail(sb); + assertEquals("1 $ equals to 30 rur.", sb.toString()); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "", + method = "replaceAll", + args = {java.lang.String.class} + ) + public void testReplaceAll() { + String input = "aabfooaabfooabfoob"; + String pattern = "a*b"; + Pattern pat = Pattern.compile(pattern); + Matcher mat = pat.matcher(input); + + assertEquals("-foo-foo-foo-", mat.replaceAll("-")); + } + + /** + * @test java.util.regex.Matcher#reset(String) + * test reset(String) method. + */ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Verifies the reset(CharSequence input) method.", + method = "reset", + args = {java.lang.CharSequence.class} + ) + public void test_resetLjava_lang_String() { + String testPattern = "(abb)"; + String testString1 = "babbabbcccabbabbabbabbabb"; + String testString2 = "cddcddcddcddcddbbbb"; + Pattern pat = Pattern.compile(testPattern); + Matcher mat = pat.matcher(testString1); + + while (mat.find()); + assertEquals("Reset should return itself 1", mat, mat.reset(testString2)); + assertFalse("After reset matcher should not find pattern in given input", mat.find()); + assertEquals("Reset should return itself 2", mat, mat.reset(testString1)); + assertTrue("After reset matcher should find pattern in given input", mat.find()); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "", + method = "appendReplacement", + args = {java.lang.StringBuffer.class, java.lang.String.class} + ) + public void testAppendSlashes() { + Pattern p = Pattern.compile("\\\\"); + Matcher m = p.matcher("one\\cat\\two\\cats\\in\\the\\yard"); + StringBuffer sb = new StringBuffer(); + while (m.find()) { + m.appendReplacement(sb, "\\\\"); + } + m.appendTail(sb); + assertEquals("one\\cat\\two\\cats\\in\\the\\yard", sb.toString()); + + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "", + method = "appendTail", + args = {java.lang.StringBuffer.class} + ) + public void testAppendTail() { + Pattern p = Pattern.compile("cat"); + Matcher m = p.matcher("one-cat-two-cats-in-the-yard"); + StringBuffer sb = new StringBuffer(); + while (m.find()) { + m.appendReplacement(sb, "dog"); + } + m.appendTail(sb); + assertEquals("one-dog-two-dogs-in-the-yard", sb.toString()); + + p = Pattern.compile("cat|yard"); + m = p.matcher("one-cat-two-cats-in-the-yard"); + sb = new StringBuffer(); + while (m.find()) { + m.appendReplacement(sb, "dog"); + } + assertEquals("one-dog-two-dogs-in-the-dog", sb.toString()); + m.appendTail(sb); + assertEquals("one-dog-two-dogs-in-the-dog", sb.toString()); + + p = Pattern.compile("cat"); + m = p.matcher("one-cat-two-cats-in-the-yard"); + sb = new StringBuffer(); + while (m.find()) { + m.appendReplacement(sb, "dog"); + } + Throwable t = null; + try { + m.appendTail(null); + } catch (NullPointerException e) { + t = e; + } + assertNotNull(t); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies replaceFirst(String replacement) method. ", + method = "replaceFirst", + args = {java.lang.String.class} + ) + public void testReplaceFirst() { + String input = "zzzdogzzzdogzzz"; + String pattern = "dog"; + Pattern pat = Pattern.compile(pattern); + Matcher mat = pat.matcher(input); + + assertEquals("zzzcatzzzdogzzz", mat.replaceFirst("cat")); + } + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Verifies pattern() method.", + method = "pattern", + args = {} + ) + public void testPattern() { + for (String element : testPatterns) { + Pattern test = Pattern.compile(element); + assertEquals(test, test.matcher("aaa").pattern()); + } + + for (String element : testPatterns) { + assertEquals(element, Pattern.compile(element).matcher("aaa") + .pattern().toString()); + } + } + + /** + * @test java.util.regex.Matcher#reset() + * test reset() method. + */ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Verifies the reset() method. ", + method = "reset", + args = {} + ) + public void test_reset() { + String testPattern = "(abb)"; + String testString = "babbabbcccabbabbabbabbabb"; + Pattern pat = Pattern.compile(testPattern); + Matcher mat = pat.matcher(testString); + + while (mat.find()); + assertEquals("Reset should return itself", mat, mat.reset()); + assertTrue("After reset matcher should find pattern in given input", mat.find()); + } + + /* + * Class under test for String group(int) + */ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies group(int group) method.", + method = "group", + args = {int.class} + ) + public void testGroupint() { + String positiveTestString = "ababababbaaabb"; + String negativeTestString = "gjhfgdsjfhgcbv"; + + // test IndexOutOfBoundsException + // // + for (int i = 0; i < groupPatterns.length; i++) { + Pattern test = Pattern.compile(groupPatterns[i]); + Matcher mat = test.matcher(positiveTestString); + mat.matches(); + try { + // groupPattern <index + 1> equals to number of groups + // of the specified pattern + // // + mat.group(i + 2); + fail("IndexOutBoundsException expected"); + mat.group(i + 100); + fail("IndexOutBoundsException expected"); + mat.group(-1); + fail("IndexOutBoundsException expected"); + mat.group(-100); + fail("IndexOutBoundsException expected"); + } catch (IndexOutOfBoundsException iobe) { + } + } + + String[][] groupResults = { { "a" }, { "a", "a" }, + { "ababababba", "a", "abb" }, { "ababababba", "a", "a", "b" }, + { "ababababba", "a", "a", "b", "b" }, + { "ababababba", "a", "a", "b", "abb", "b" }, }; + + for (int i = 0; i < groupPatterns.length; i++) { + Pattern test = Pattern.compile(groupPatterns[i]); + Matcher mat = test.matcher(positiveTestString); + mat.matches(); + for (int j = 0; j < groupResults[i].length; j++) { + assertEquals("i: " + i + " j: " + j, groupResults[i][j], mat + .group(j + 1)); + } + + } + + } + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies group() and group(int group) methods.", + method = "group", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies group() and group(int group) methods.", + method = "group", + args = {int.class} + ) + }) + public void testGroup() { + String positiveTestString = "ababababbaaabb"; + String negativeTestString = "gjhfgdsjfhgcbv"; + for (String element : groupPatterns) { + Pattern test = Pattern.compile(element); + Matcher mat = test.matcher(positiveTestString); + mat.matches(); + // test result + assertEquals(positiveTestString, mat.group()); + + // test equal to group(0) result + assertEquals(mat.group(0), mat.group()); + } + + for (String element : groupPatterns) { + Pattern test = Pattern.compile(element); + Matcher mat = test.matcher(negativeTestString); + mat.matches(); + try { + mat.group(); + fail("IllegalStateException expected for <false> matches result"); + } catch (IllegalStateException ise) { + } + } + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies group(int group) method.", + method = "group", + args = {int.class} + ) + public void testGroupPossessive() { + Pattern pat = Pattern.compile("((a)|(b))++c"); + Matcher mat = pat.matcher("aac"); + + mat.matches(); + assertEquals("a", mat.group(1)); + } + + /** + * @test java.util.regex.Matcher#hasAnchoringBounds() + * test hasAnchoringBounds() method. + */ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Verifies that hasAnchoringBounds method returns correct value.", + method = "hasAnchoringBounds", + args = {} + ) + public void test_hasAnchoringBounds() { + String testPattern = "abb"; + String testString = "abb"; + Pattern pat = Pattern.compile(testPattern); + Matcher mat = pat.matcher(testString); + + assertTrue("Matcher uses anchoring bound by default", + mat.hasAnchoringBounds()); + + Matcher mu = mat.useAnchoringBounds(true); + assertTrue("Incorrect value of anchoring bounds", + mu.hasAnchoringBounds()); + + mu = mat.useAnchoringBounds(false); + assertFalse("Incorrect value of anchoring bounds", + mu.hasAnchoringBounds()); + } + + /** + * @test java.util.regex.Matcher#hasTransparentBounds() + * test hasTransparentBounds() method. + */ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Verifies that hasTransparentBound method returns correct value.", + method = "hasTransparentBounds", + args = {} + ) + public void test_hasTransparentBounds() { + String testPattern = "abb"; + String testString = "ab\nb"; + Pattern pat = Pattern.compile(testPattern); + Matcher mat = pat.matcher(testString); + + assertFalse("Matcher uses opaque bounds by default", + mat.hasTransparentBounds()); + + Matcher mu = mat.useTransparentBounds(true); + assertTrue("Incorrect value of anchoring bounds", + mu.hasTransparentBounds()); + + mu = mat.useTransparentBounds(false); + assertFalse("Incorrect value of anchoring bounds", + mu.hasTransparentBounds()); + } + + /** + * @test java.util.regex.Matcher#start(int) + * test start(int) method. + */ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the start(int group) method.", + method = "start", + args = {int.class} + ) + public void test_startI() { + String testPattern = "(((abb)a)(bb))"; + String testString = "cccabbabbabbabbabb"; + Pattern pat = Pattern.compile(testPattern); + Matcher mat = pat.matcher(testString); + int start = 3; + int end = 6; + int i, j; + + for (j = 0; j < 3; j++) { + while (mat.find(start + j - 2)) { + for (i = 0; i < 4; i++) { + assertEquals("Start is wrong for group " + i + " :" + mat.group(i), start, mat.start(i)); + } + assertEquals("Start is wrong for group " + i + " :" + mat.group(i), start + 4, mat.start(i)); + + start = end; + end += 3; + } + } + } + + /** + * @test java.util.regex.Matcher#end(int) + * test end(int) method. + */ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the basic functionality of end(int group) method.", + method = "end", + args = {int.class} + ) + public void test_endI() { + String testPattern = "(((abb)a)(bb))"; + String testString = "cccabbabbabbabbabb"; + Pattern pat = Pattern.compile(testPattern); + Matcher mat = pat.matcher(testString); + int start = 3; + int end = 6; + int i, j; + + for (j = 0; j < 3; j++) { + while (mat.find(start + j - 2)) { + for (i = 0; i < 4; i++) { + assertEquals("End is wrong for group " + i + " :" + mat.group(i), start + mat.group(i).length(), mat.end(i)); + } + assertEquals("End is wrong for group " + i + " :" + mat.group(i), start + 4 + mat.group(i).length(), mat.end(i)); + + start = end; + end += 3; + } + } + } + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies matches() method in miscellaneous cases.", + method = "matches", + args = {} + ) + public void testMatchesMisc() { + String[][] posSeq = { + { "abb", "ababb", "abababbababb", "abababbababbabababbbbbabb" }, + { "213567", "12324567", "1234567", "213213567", + "21312312312567", "444444567" }, + { "abcdaab", "aab", "abaab", "cdaab", "acbdadcbaab" }, + { "213234567", "3458", "0987654", "7689546432", "0398576", + "98432", "5" }, + { + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" }, + { "ababbaAabababblice", "ababbaAliceababab", "ababbAabliceaaa", + "abbbAbbbliceaaa", "Alice" }, + { "a123", "bnxnvgds156", "for", "while", "if", "struct" } + + }; + + for (int i = 0; i < testPatterns.length; i++) { + Pattern pat = Pattern.compile(testPatterns[i]); + for (int j = 0; j < posSeq[i].length; j++) { + Matcher mat = pat.matcher(posSeq[i][j]); + assertTrue("Incorrect match: " + testPatterns[i] + " vs " + + posSeq[i][j], mat.matches()); + } + } + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Stress test for matches() method.", + method = "matches", + args = {} + ) + public void testMatchesQuantifiers() { + String[] testPatternsSingles = { "a{5}", "a{2,4}", "a{3,}" }; + String[] testPatternsMultiple = { "((a)|(b)){1,2}abb", + "((a)|(b)){2,4}", "((a)|(b)){3,}" }; + + String[][] stringSingles = { { "aaaaa", "aaa" }, + { "aa", "a", "aaa", "aaaaaa", "aaaa", "aaaaa" }, + { "aaa", "a", "aaaa", "aa" }, }; + + String[][] stringMultiples = { { "ababb", "aba" }, + { "ab", "b", "bab", "ababa", "abba", "abababbb" }, + { "aba", "b", "abaa", "ba" }, }; + + for (int i = 0; i < testPatternsSingles.length; i++) { + Pattern pat = Pattern.compile(testPatternsSingles[i]); + for (int j = 0; j < stringSingles.length / 2; j++) { + assertTrue("Match expected, but failed: " + pat.pattern() + + " : " + stringSingles[i][j], pat.matcher( + stringSingles[i][j * 2]).matches()); + assertFalse("Match failure expected, but match succeed: " + + pat.pattern() + " : " + stringSingles[i][j * 2 + 1], + pat.matcher(stringSingles[i][j * 2 + 1]).matches()); + } + } + + for (int i = 0; i < testPatternsMultiple.length; i++) { + Pattern pat = Pattern.compile(testPatternsMultiple[i]); + for (int j = 0; j < stringMultiples.length / 2; j++) { + assertTrue("Match expected, but failed: " + pat.pattern() + + " : " + stringMultiples[i][j], pat.matcher( + stringMultiples[i][j * 2]).matches()); + assertFalse( + "Match failure expected, but match succeed: " + + pat.pattern() + " : " + + stringMultiples[i][j * 2 + 1], pat.matcher( + stringMultiples[i][j * 2 + 1]).matches()); + } + } + } + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies matches() and group(int group) methods for specific pattern.", + method = "matches", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies matches() and group(int group) methods for specific pattern.", + method = "group", + args = {int.class} + ) + }) + public void testQuantVsGroup() { + String patternString = "(d{1,3})((a|c)*)(d{1,3})((a|c)*)(d{1,3})"; + String testString = "dacaacaacaaddaaacaacaaddd"; + + Pattern pat = Pattern.compile(patternString); + Matcher mat = pat.matcher(testString); + + mat.matches(); + assertEquals("dacaacaacaaddaaacaacaaddd", mat.group()); + assertEquals("d", mat.group(1)); + assertEquals("acaacaacaa", mat.group(2)); + assertEquals("dd", mat.group(4)); + assertEquals("aaacaacaa", mat.group(5)); + assertEquals("ddd", mat.group(7)); + } + + /** + * @test java.util.regex.Matcher#lookingAt() + * test lookingAt() method. + */ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Verifies that lookingAt() method returns correct value.", + method = "lookingAt", + args = {} + ) + public void test_lookingAt() { + String testPattern = "(((abb)a)(bb))"; + String testString1 = "babbabbcccabbabbabbabbabb"; + String testString2 = "abbabb"; + Pattern pat = Pattern.compile(testPattern); + Matcher mat1 = pat.matcher(testString1); + Matcher mat2 = pat.matcher(testString2); + + assertFalse("Should not find given pattern in 1 string", mat1.lookingAt()); + mat1.region(1, 10); + assertTrue("Should find given pattern in region of string", mat1.lookingAt()); + assertTrue("Should find given pattern in 2 string", mat2.lookingAt()); + } + + /* + * Class under test for boolean find() + */ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies that find() method returns correct value.", + method = "find", + args = {} + ) + public void testFind() { + String testPattern = "(abb)"; + String testString = "cccabbabbabbabbabb"; + Pattern pat = Pattern.compile(testPattern); + Matcher mat = pat.matcher(testString); + int start = 3; + int end = 6; + while (mat.find()) { + assertEquals(start, mat.start(1)); + assertEquals(end, mat.end(1)); + + start = end; + end += 3; + } + + testPattern = "(\\d{1,3})"; + testString = "aaaa123456789045"; + + Pattern pat2 = Pattern.compile(testPattern); + Matcher mat2 = pat2.matcher(testString); + start = 4; + int length = 3; + while (mat2.find()) { + assertEquals(testString.substring(start, start + length), mat2 + .group(1)); + start += length; + } + } + + /** + * @test java.util.regex.Matcher#find(int) + * test find (int) method. Created via modifying method for find + */ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "", + method = "find", + args = {int.class} + ) + public void test_findI() { + String testPattern = "(abb)"; + String testString = "cccabbabbabbabbabb"; + Pattern pat = Pattern.compile(testPattern); + Matcher mat = pat.matcher(testString); + int start = 3; + int end = 6; + int j; + + for (j = 0; j < 3; j++) { + while (mat.find(start + j - 2)) { + assertEquals(start, mat.start(1)); + assertEquals(end, mat.end(1)); + + start = end; + end += 3; + } + start = 6; + end = 9; + } + + testPattern = "(\\d{1,3})"; + testString = "aaaa123456789045"; + + Pattern pat2 = Pattern.compile(testPattern); + Matcher mat2 = pat2.matcher(testString); + start = 4; + int length = 3; + for (j = 0; j < length; j++) { + for (int i = 4 + j; i < testString.length() - length; i += length) { + mat2.find(i); + assertEquals(testString.substring(i, i + length), mat2.group(1)); + } + } + + // Starting index out of region + Pattern pat3 = Pattern.compile("new"); + Matcher mat3 = pat3.matcher("Brave new world"); + + assertTrue(mat3.find(-1)); + assertTrue(mat3.find(6)); + assertFalse(mat3.find(7)); + + mat3.region(7, 10); + + assertFalse(mat3.find(3)); + assertFalse(mat3.find(6)); + assertFalse(mat3.find(7)); + } + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies matches() method for predefined.", + method = "replaceFirst", + args = {java.lang.String.class} + ) + public void testSEOLsymbols() { + Pattern pat = Pattern.compile("^a\\(bb\\[$"); + Matcher mat = pat.matcher("a(bb["); + + assertTrue(mat.matches()); + } + + /** + * @test java.util.regex.Matcher#start() + * test start() method. + */ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the start() method.", + method = "start", + args = {} + ) + public void test_start() { + String testPattern = "(abb)"; + String testString = "cccabbabbabbabbabb"; + Pattern pat = Pattern.compile(testPattern); + Matcher mat = pat.matcher(testString); + int start = 3; + int end = 6; + int j; + + for (j = 0; j < 3; j++) { + while (mat.find()) { + assertEquals("Start is wrong", start, mat.start()); + + start = end; + end += 3; + } + } + } + + /** + * @test java.util.regex.Matcher#end() + * test end() method. + */ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the basic functionality of end() method. ", + method = "end", + args = {} + ) + public void test_end() { + String testPattern = "(abb)"; + String testString = "cccabbabbabbabbabb"; + Pattern pat = Pattern.compile(testPattern); + Matcher mat = pat.matcher(testString); + int start = 3; + int end = 6; + int j; + + for (j = 0; j < 3; j++) { + while (mat.find()) { + assertEquals("Start is wrong", end, mat.end()); + + start = end; + end += 3; + } + } + } + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Verifies groupCount() method.", + method = "groupCount", + args = {} + ) + public void testGroupCount() { + for (int i = 0; i < groupPatterns.length; i++) { + Pattern test = Pattern.compile(groupPatterns[i]); + Matcher mat = test.matcher("ababababbaaabb"); + mat.matches(); + assertEquals(i + 1, mat.groupCount()); + } + } + + + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "", + method = "region", + args = {int.class, int.class} + ) + public void testRegion() { + Pattern p = Pattern.compile("abba"); + Matcher m = p.matcher("Gabba gabba hey"); + + m.region(0, 15); + assertTrue(m.find()); + assertTrue(m.find()); + assertFalse(m.find()); + + m.region(5, 15); + assertTrue(m.find()); + assertFalse(m.find()); + + m.region(10, 15); + assertFalse(m.find()); + + Throwable t = null; + + try { + m.region(-1, 15); + } catch (IllegalArgumentException e) { + t = e; + } + assertNotNull(t); + + t = null; + try { + m.region(0, 16); + } catch (IllegalArgumentException e) { + t = e; + } + assertNotNull(t); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies matches() and group(int group) methods for specific pattern.", + method = "matches", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies matches() and group(int group) methods for specific pattern.", + method = "group", + args = {int.class} + ) + }) + public void testRelactantQuantifiers() { + Pattern pat = Pattern.compile("(ab*)*b"); + Matcher mat = pat.matcher("abbbb"); + + if (mat.matches()) { + assertEquals("abbb", mat.group(1)); + } else { + fail("Match expected: (ab*)*b vs abbbb"); + } + } + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies find() method.", + method = "find", + args = {} + ) + public void testEnhancedFind() { + String input = "foob"; + String pattern = "a*b"; + Pattern pat = Pattern.compile(pattern); + Matcher mat = pat.matcher(input); + + mat.find(); + assertEquals("b", mat.group()); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies matches method for input sequence specified by URL.", + method = "matches", + args = {} + ) + public void testMatchesURI() { + Pattern pat = Pattern. + compile("^(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"); + Matcher mat = pat + .matcher("file:/c:/workspace/api/build.win32/classes/META-INF/" + + "services/javax.xml.parsers.DocumentBuilderFactory"); + assertTrue(mat.matches()); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies matches() method for composite pattern groups.", + method = "matches", + args = {} + ) + public void testPosCompositeGroup() { + String[] posExamples = { "aabbcc", "aacc", "bbaabbcc" }; + String[] negExamples = { "aabb", "bb", "bbaabb" }; + Pattern posPat = Pattern.compile("(aa|bb){1,3}+cc"); + Pattern negPat = Pattern.compile("(aa|bb){1,3}+bb"); + + Matcher mat; + for (String element : posExamples) { + mat = posPat.matcher(element); + assertTrue(mat.matches()); + } + + for (String element : negExamples) { + mat = negPat.matcher(element); + assertFalse(mat.matches()); + } + + assertTrue(Pattern.matches("(aa|bb){1,3}+bb", "aabbaabb")); + + } + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies matches() method for specific patterns.", + method = "matches", + args = {} + ) + public void testPosAltGroup() { + String[] posExamples = { "aacc", "bbcc", "cc" }; + String[] negExamples = { "bb", "aa" }; + Pattern posPat = Pattern.compile("(aa|bb)?+cc"); + Pattern negPat = Pattern.compile("(aa|bb)?+bb"); + + Matcher mat; + for (String element : posExamples) { + mat = posPat.matcher(element); + assertTrue(posPat.toString() + " vs: " + element, mat.matches()); + } + + for (String element : negExamples) { + mat = negPat.matcher(element); + assertFalse(mat.matches()); + } + + assertTrue(Pattern.matches("(aa|bb)?+bb", "aabb")); + } + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies matches() and group(int group) methods for specific pattern.", + method = "matches", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies matches() and group(int group) methods for specific pattern.", + method = "group", + args = {int.class} + ) + }) + public void testRelCompGroup() { + + Matcher mat; + Pattern pat; + String res = ""; + for (int i = 0; i < 4; i++) { + pat = Pattern.compile("((aa|bb){" + i + ",3}?).*cc"); + mat = pat.matcher("aaaaaacc"); + assertTrue(pat.toString() + " vs: " + "aaaaaacc", mat.matches()); + assertEquals(res, mat.group(1)); + res += "aa"; + } + } + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies matches() and group(int group) methods for specific pattern.", + method = "matches", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies matches() and group(int group) methods for specific pattern.", + method = "group", + args = {int.class} + ) + }) + public void testRelAltGroup() { + + Matcher mat; + Pattern pat; + + pat = Pattern.compile("((aa|bb)??).*cc"); + mat = pat.matcher("aacc"); + assertTrue(pat.toString() + " vs: " + "aacc", mat.matches()); + assertEquals("", mat.group(1)); + + pat = Pattern.compile("((aa|bb)??)cc"); + mat = pat.matcher("aacc"); + assertTrue(pat.toString() + " vs: " + "aacc", mat.matches()); + assertEquals("aa", mat.group(1)); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies matches() method for case insensitive pattern.", + method = "matches", + args = {} + ) + public void testIgnoreCase() { + Pattern pat = Pattern.compile("(aa|bb)*", Pattern.CASE_INSENSITIVE); + Matcher mat = pat.matcher("aAbb"); + + assertTrue(mat.matches()); + + pat = Pattern.compile("(a|b|c|d|e)*", Pattern.CASE_INSENSITIVE); + mat = pat.matcher("aAebbAEaEdebbedEccEdebbedEaedaebEbdCCdbBDcdcdADa"); + assertTrue(mat.matches()); + + pat = Pattern.compile("[a-e]*", Pattern.CASE_INSENSITIVE); + mat = pat.matcher("aAebbAEaEdebbedEccEdebbedEaedaebEbdCCdbBDcdcdADa"); + assertTrue(mat.matches()); + + } + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "", + method = "quoteReplacement", + args = {java.lang.String.class} + ) + public void testQuoteReplacement() { + assertEquals("\\$dollar and slash\\\\", Matcher.quoteReplacement("$dollar and slash\\")); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies matches() and group(int group) methods.", + method = "matches", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies matches() and group(int group) methods.", + method = "group", + args = {int.class} + ) + }) + public void testOverFlow() { + Pattern tp = Pattern.compile("(a*)*"); + Matcher tm = tp.matcher("aaa"); + assertTrue(tm.matches()); + assertEquals("", tm.group(1)); + + assertTrue(Pattern.matches("(1+)\\1+", "11")); + assertTrue(Pattern.matches("(1+)(2*)\\2+", "11")); + + Pattern pat = Pattern.compile("(1+)\\1*"); + Matcher mat = pat.matcher("11"); + + assertTrue(mat.matches()); + assertEquals("11", mat.group(1)); + + pat = Pattern.compile("((1+)|(2+))(\\2+)"); + mat = pat.matcher("11"); + + assertTrue(mat.matches()); + assertEquals("1", mat.group(2)); + assertEquals("1", mat.group(1)); + assertEquals("1", mat.group(4)); + assertNull(mat.group(3)); + + } + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "", + method = "matches", + args = {} + ) + public void testUnicode() { + + assertTrue(Pattern.compile("\\x61a").matcher("aa").matches()); +// assertTrue(Pattern.matches("\\u0061a", "aa")); + assertTrue(Pattern.compile("\\0141a").matcher("aa").matches()); + assertTrue(Pattern.compile("\\0777").matcher("?7").matches()); + + } + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "", + method = "matches", + args = {} + ) + public void testUnicodeCategory() { + assertTrue(Pattern.compile("\\p{Ll}").matcher("k").matches()); // Unicode lower case + assertTrue(Pattern.compile("\\P{Ll}").matcher("K").matches()); // Unicode non-lower + // case + assertTrue(Pattern.compile("\\p{Lu}").matcher("K").matches()); // Unicode upper case + assertTrue(Pattern.compile("\\P{Lu}").matcher("k").matches()); // Unicode non-upper + // case + // combinations + assertTrue(Pattern.compile("[\\p{L}&&[^\\p{Lu}]]").matcher("k").matches()); + assertTrue(Pattern.compile("[\\p{L}&&[^\\p{Ll}]]").matcher("K").matches()); + assertFalse(Pattern.compile("[\\p{L}&&[^\\p{Lu}]]").matcher("K").matches()); + assertFalse(Pattern.compile("[\\p{L}&&[^\\p{Ll}]]").matcher("k").matches()); + + // category/character combinations + assertFalse(Pattern.compile("[\\p{L}&&[^a-z]]").matcher("k").matches()); + assertTrue(Pattern.compile("[\\p{L}&&[^a-z]]").matcher("K").matches()); + + assertTrue(Pattern.compile("[\\p{Lu}a-z]").matcher("k").matches()); + assertTrue(Pattern.compile("[a-z\\p{Lu}]").matcher("k").matches()); + + assertFalse(Pattern.compile("[\\p{Lu}a-d]").matcher("k").matches()); + assertTrue(Pattern.compile("[a-d\\p{Lu}]").matcher("K").matches()); + + // assertTrue(Pattern.matches("[\\p{L}&&[^\\p{Lu}&&[^K]]]", "K")); + assertFalse(Pattern.compile("[\\p{L}&&[^\\p{Lu}&&[^G]]]").matcher("K").matches()); + + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies that find() method works correctly with $ pattern.", + method = "find", + args = {} + ) + public void testFindDollar() { + Matcher mat = Pattern.compile("a$").matcher("a\n"); + assertTrue(mat.find()); + assertEquals("a", mat.group()); + } + + /* + * Verify if the Matcher can match the input when region is changed + */ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies matches() method for the specified region.", + method = "matches", + args = {} + ) + public void testMatchesRegionChanged() { + // Regression for HARMONY-610 + String input = " word "; + Pattern pattern = Pattern.compile("\\w+"); + Matcher matcher = pattern.matcher(input); + matcher.region(1, 5); + assertTrue(matcher.matches()); + } + + // BEGIN android-note + // Test took ages, now going in steps of 16 code points to speed things up. + // END android-note + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "The stress test for matches(String regex) method from String class.", + clazz = String.class, + method = "matches", + args = {java.lang.String.class} + ) + public void testAllCodePoints() { + // Regression for HARMONY-3145 + int[] codePoint = new int[1]; + Pattern p = Pattern.compile("(\\p{all})+"); + boolean res = true; + int cnt = 0; + String s; + for (int i = 0; i < 0x110000; i = i + 0x10) { + codePoint[0] = i; + s = new String(codePoint, 0, 1); + if (!s.matches(p.toString())) { + cnt++; + res = false; + } + } + assertTrue(res); + assertEquals(0, cnt); + + p = Pattern.compile("(\\P{all})+"); + res = true; + cnt = 0; + + for (int i = 0; i < 0x110000; i = i + 0x10) { + codePoint[0] = i; + s = new String(codePoint, 0, 1); + if (!s.matches(p.toString())) { + cnt++; + res = false; + } + } + + assertFalse(res); + assertEquals(0x110000 / 0x10, cnt); + } + + /* + * Verify if the Matcher behaves correct when region is changed + */ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies find() method for specified region in positive case.", + method = "find", + args = {} + ) + public void testFindRegionChanged() { + // Regression for HARMONY-625 + Pattern pattern = Pattern.compile("(?s).*"); + Matcher matcher = pattern.matcher("abcde"); + matcher.find(); + assertEquals("abcde", matcher.group()); + + matcher = pattern.matcher("abcde"); + matcher.region(0, 2); + matcher.find(); + assertEquals("ab", matcher.group()); + + } + + /* + * Verify if the Matcher behaves correct with pattern "c" when region is + * changed + */ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies find() method for specified region in negative case.", + method = "find", + args = {} + ) + public void testFindRegionChanged2() { + // Regression for HARMONY-713 + Pattern pattern = Pattern.compile("c"); + + String inputStr = "aabb.c"; + Matcher matcher = pattern.matcher(inputStr); + matcher.region(0, 3); + + assertFalse(matcher.find()); + } + + /** + * @test java.util.regex.Matcher#regionStart() + * test regionStart() method. + */ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Verifies the regionStart() method.", + method = "regionStart", + args = {} + ) + public void test_regionStart() { + String testPattern = "(abb)"; + String testString = "cccabbabbabbabbabb"; + Pattern pat = Pattern.compile(testPattern); + Matcher mat = pat.matcher(testString); + + assertEquals("Region sould start from 0 position", 0, mat.regionStart()); + mat.region(1, 10); + assertEquals("Region sould start from 1 position after setting new region", 1, mat.regionStart()); + mat.reset(); + assertEquals("Region sould start from 0 position after reset", 0, mat.regionStart()); + } + + /** + * @test java.util.regex.Matcher#regionEnd() + * test regionEnd() method. + */ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Verifies the regionEnd() method.", + method = "regionEnd", + args = {} + ) + public void test_regionEnd() { + String testPattern = "(abb)"; + String testString = "cccabbabbabbabbabb"; + Pattern pat = Pattern.compile(testPattern); + Matcher mat = pat.matcher(testString); + + assertEquals("Region end value should be equal to string length", testString.length(), mat.regionEnd()); + mat.region(1, 10); + assertEquals("Region end value should be equal to 10 after setting new region", 10, mat.regionEnd()); + mat.reset(); + assertEquals("Region end value should be equal to string length after reset", testString.length(), mat.regionEnd()); + } + + /** + * @test java.util.regex.Matcher#toMatchResult() + * test toMatchResult() method. + */ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Verifies the toMatchResult method.", + method = "toMatchResult", + args = {} + ) + public void test_toMatchResult() { + String testPattern = "(((abb)a)(bb))"; + String testString = "babbabbcccabbabbabbabbabb"; + Pattern pat = Pattern.compile(testPattern); + Matcher mat = pat.matcher(testString); + + mat.region(1, 7); + assertTrue("matcher should find pattern in given region", mat.matches()); + assertEquals("matched section should start from 1 position", 1, mat.toMatchResult().start()); + assertEquals("matched section for 2 group should start from 1 position", 1, mat.toMatchResult().start(2)); + assertEquals("matched section for whole pattern should end on 7 position", 7, mat.toMatchResult().end()); + assertEquals("matched section for 3 group should end at 4 position", 4, mat.toMatchResult().end(3)); + assertEquals("group not matched", "abbabb", mat.toMatchResult().group()); + assertEquals("3 group not matched", "abb", mat.toMatchResult().group(3)); + assertEquals("Total number of groups does not matched with given pattern", 4, mat.toMatchResult().groupCount()); + } + + /** + * @test java.util.regex.Matcher#usePattern(Pattern newPattern) + * test usePattern(Pattern newPattern) method. + */ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the usePattern(Pattern newPattern) method.", + method = "usePattern", + args = {java.util.regex.Pattern.class} + ) + public void test_usePatternLjava_util_regex_Pattern() { + String testPattern1 = "(((abb)a)(bb))"; + String testPattern2 = "(abbabb)"; + String testPattern3 = "(babb)"; + String testString = "babbabbcccabbabbabbabbabb"; + Pattern pat = Pattern.compile(testPattern1); + Matcher mat = pat.matcher(testString); + + mat.region(1, 7); + assertTrue("matcher should find pattern in given region in case of groupe in pattern", mat.matches()); + assertEquals("", mat, mat.usePattern(Pattern.compile(testPattern2))); + assertTrue("matcher should find pattern in given region", mat.matches()); + assertEquals("", mat, mat.usePattern(Pattern.compile(testPattern3))); + assertFalse("matcher should not find pattern in given region", mat.matches()); + } + + /** + * @test java.util.regex.Matcher#useAchoringBounds() + * test useAchoringBounds() method. + */ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "", + method = "useAnchoringBounds", + args = {boolean.class} + ) + public void test_anchoringBounds() { + String testPattern = "^ro$"; + String testString = "android"; + Pattern pat = Pattern.compile(testPattern); + Matcher mat = pat.matcher(testString); + + mat.region(2, 5); + mat.useAnchoringBounds(false); + assertFalse("Shouldn't find pattern with non-anchoring bounds", mat.find(0)); + + mat.region(2, 5); + mat.useAnchoringBounds(true); + assertFalse("Should find pattern with anchoring bounds", mat.find(0)); + } + + /** + * @test java.util.regex.Matcher#useTransparentBounds() + * test useTransparentBounds() method. + */ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Verifies the useTransparentBounds(boolean b) method.", + method = "useTransparentBounds", + args = {boolean.class} + ) + public void test_transparentBounds() { + String testPattern = "and(?=roid)"; + String testString = "android"; + Pattern pat = Pattern.compile(testPattern); + Matcher mat = pat.matcher(testString); + + mat.region(0, 3); + mat.useTransparentBounds(false); + assertFalse("Shouldn't find pattern with opaque bounds", mat.matches()); + + mat.useTransparentBounds(true); + assertTrue("Should find pattern transparent bounds", mat.matches()); // *** + + testPattern = "and(?!roid)"; + testString = "android"; + pat = Pattern.compile(testPattern); + mat = pat.matcher(testString); + + mat.region(0, 3); + mat.useTransparentBounds(false); + assertTrue("Should find pattern with opaque bounds", mat.matches()); + + mat.useTransparentBounds(true); + assertFalse("Shouldn't find pattern transparent bounds", mat.matches()); // *** + } + + /** + * @test java.util.regex.Matcher#hitEnd() + * test hitEnd() method. + */ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Verifies that hitEnd() method returns correct value. ", + method = "hitEnd", + args = {} + ) + public void test_hitEnd() { + String testPattern = "abb"; + String testString = "babbabbcccabbabbabbabbabb"; + Pattern pat = Pattern.compile(testPattern); + Matcher mat = pat.matcher(testString); + + while (mat.find()) { + assertFalse("hitEnd should return false during parsing input", mat.hitEnd()); + } + assertTrue("hitEnd should return true after finding last match", mat.hitEnd()); // *** + } + + /** + * @test java.util.regex.Matcher#requireEnd() + * test requireEnd() method. + */ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Verifies the requireEnd() method.", + method = "requireEnd", + args = {} + ) + public void test_requireEnd() { + String testPattern = "bba"; + String testString = "abbbbba"; + Pattern pat = Pattern.compile(testPattern); + Matcher mat = pat.matcher(testString); + + assertTrue(mat.find()); + assertFalse(mat.requireEnd()); + + testPattern = "bba$"; + testString = "abbbbba"; + pat = Pattern.compile(testPattern); + mat = pat.matcher(testString); + + assertTrue(mat.find()); + assertTrue(mat.requireEnd()); + } + + /* + * Regression test for HARMONY-674 + */ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Special regression test for matches() method.", + method = "matches", + args = {} + ) + public void testPatternMatcher() throws Exception { + Pattern pattern = Pattern.compile("(?:\\d+)(?:pt)"); + assertTrue(pattern.matcher("14pt").matches()); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(MatcherTest.class); + } + +} diff --git a/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/ModeTest.java b/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/ModeTest.java new file mode 100644 index 0000000..bad03f7 --- /dev/null +++ b/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/ModeTest.java @@ -0,0 +1,150 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.harmony.regex.tests.java.util.regex; + +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestLevel; + +import junit.framework.TestCase; +import java.util.regex.Pattern; +import java.util.regex.Matcher; +import java.util.regex.PatternSyntaxException; + +/** + * Tests Pattern compilation modes and modes triggered in pattern strings + * + */ +@TestTargetClass(Pattern.class) +public class ModeTest extends TestCase { + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "The test verifies compile(String regex) and compile(String regex, int flags) methods with Pattern.CASE_INSENSITIVE mode.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "The test verifies compile(String regex) and compile(String regex, int flags) methods with Pattern.CASE_INSENSITIVE mode.", + method = "compile", + args = {java.lang.String.class, int.class} + ) + }) + public void testCase() throws PatternSyntaxException { + Pattern p; + Matcher m; + + p = Pattern.compile("([a-z]+)[0-9]+"); + m = p.matcher("cAT123#dog345"); + assertTrue(m.find()); + assertEquals("dog", m.group(1)); + assertFalse(m.find()); + + + p = Pattern.compile("([a-z]+)[0-9]+", Pattern.CASE_INSENSITIVE); + m = p.matcher("cAt123#doG345"); + assertTrue(m.find()); + assertEquals("cAt", m.group(1)); + assertTrue(m.find()); + assertEquals("doG", m.group(1)); + assertFalse(m.find()); + + + p = Pattern.compile("(?i)([a-z]+)[0-9]+"); + m = p.matcher("cAt123#doG345"); + assertTrue(m.find()); + assertEquals("cAt", m.group(1)); + assertTrue(m.find()); + assertEquals("doG", m.group(1)); + assertFalse(m.find()); + } + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "The test verifies compile(String regex) and compile(String regex, int flags) methods with Pattern.MULTILINE mode.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "The test verifies compile(String regex) and compile(String regex, int flags) methods with Pattern.MULTILINE mode.", + method = "compile", + args = {java.lang.String.class, int.class} + ) + }) + public void testMultiline() throws PatternSyntaxException { + Pattern p; + Matcher m; + + p = Pattern.compile("^foo"); + m = p.matcher("foobar"); + assertTrue(m.find()); + assertTrue(m.start() == 0 && m.end() == 3); + assertFalse(m.find()); + + m = p.matcher("barfoo"); + assertFalse(m.find()); + + + p = Pattern.compile("foo$"); + m = p.matcher("foobar"); + assertFalse(m.find()); + + m = p.matcher("barfoo"); + assertTrue(m.find()); + assertTrue(m.start() == 3 && m.end() == 6); + assertFalse(m.find()); + + + p = Pattern.compile("^foo([0-9]*)", Pattern.MULTILINE); + m = p.matcher("foo1bar\nfoo2foo3\nbarfoo4"); + assertTrue(m.find()); + assertEquals("1", m.group(1)); + assertTrue(m.find()); + assertEquals("2", m.group(1)); + assertFalse(m.find()); + + + p = Pattern.compile("foo([0-9]*)$", Pattern.MULTILINE); + m = p.matcher("foo1bar\nfoo2foo3\nbarfoo4"); + assertTrue(m.find()); + assertEquals("3", m.group(1)); + assertTrue(m.find()); + assertEquals("4", m.group(1)); + assertFalse(m.find()); + + + p = Pattern.compile("(?m)^foo([0-9]*)"); + m = p.matcher("foo1bar\nfoo2foo3\nbarfoo4"); + assertTrue(m.find()); + assertEquals("1", m.group(1)); + assertTrue(m.find()); + assertEquals("2", m.group(1)); + assertFalse(m.find()); + + p = Pattern.compile("(?m)foo([0-9]*)$"); + m = p.matcher("foo1bar\nfoo2foo3\nbarfoo4"); + assertTrue(m.find()); + assertEquals("3", m.group(1)); + assertTrue(m.find()); + assertEquals("4", m.group(1)); + assertFalse(m.find()); + } +} diff --git a/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/Pattern2Test.java b/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/Pattern2Test.java new file mode 100644 index 0000000..10d2534 --- /dev/null +++ b/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/Pattern2Test.java @@ -0,0 +1,1611 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.harmony.regex.tests.java.util.regex; + +import dalvik.annotation.BrokenTest; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestLevel; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import junit.framework.TestCase; +@TestTargetClass(Pattern.class) +/** + * Tests simple Pattern compilation and Matcher methods + * + */ +public class Pattern2Test extends TestCase { + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies matches(String regex, CharSequence input) method.", + method = "matches", + args = {java.lang.String.class, java.lang.CharSequence.class} + ) + public void testSimpleMatch() throws PatternSyntaxException { + Pattern p = Pattern.compile("foo.*"); + + Matcher m1 = p.matcher("foo123"); + assertTrue(m1.matches()); + assertTrue(m1.find(0)); + assertTrue(m1.lookingAt()); + + Matcher m2 = p.matcher("fox"); + assertFalse(m2.matches()); + assertFalse(m2.find(0)); + assertFalse(m2.lookingAt()); + + assertTrue(Pattern.matches("foo.*", "foo123")); + assertFalse(Pattern.matches("foo.*", "fox")); + + assertFalse(Pattern.matches("bar", "foobar")); + + assertTrue(Pattern.matches("", "")); + } + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies compile(String regex) method and matcher for created pattern.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies compile(String regex) method and matcher for created pattern.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testCursors() { + Pattern p; + Matcher m; + + try { + p = Pattern.compile("foo"); + + m = p.matcher("foobar"); + assertTrue(m.find()); + assertEquals(0, m.start()); + assertEquals(3, m.end()); + assertFalse(m.find()); + + // Note: also testing reset here + m.reset(); + assertTrue(m.find()); + assertEquals(0, m.start()); + assertEquals(3, m.end()); + assertFalse(m.find()); + + m.reset("barfoobar"); + assertTrue(m.find()); + assertEquals(3, m.start()); + assertEquals(6, m.end()); + assertFalse(m.find()); + + m.reset("barfoo"); + assertTrue(m.find()); + assertEquals(3, m.start()); + assertEquals(6, m.end()); + assertFalse(m.find()); + + m.reset("foobarfoobarfoo"); + assertTrue(m.find()); + assertEquals(0, m.start()); + assertEquals(3, m.end()); + assertTrue(m.find()); + assertEquals(6, m.start()); + assertEquals(9, m.end()); + assertTrue(m.find()); + assertEquals(12, m.start()); + assertEquals(15, m.end()); + assertFalse(m.find()); + assertTrue(m.find(0)); + assertEquals(0, m.start()); + assertEquals(3, m.end()); + assertTrue(m.find(4)); + assertEquals(6, m.start()); + assertEquals(9, m.end()); + } catch (PatternSyntaxException e) { + System.out.println(e.getMessage()); + fail(); + } + } + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies compile(String regex) method and matcher for created pattern.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies compile(String regex) method and matcher for created pattern.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testGroups() throws PatternSyntaxException { + Pattern p; + Matcher m; + + p = Pattern.compile("(p[0-9]*)#?(q[0-9]*)"); + + m = p.matcher("p1#q3p2q42p5p71p63#q888"); + assertTrue(m.find()); + assertEquals(0, m.start()); + assertEquals(5, m.end()); + assertEquals(2, m.groupCount()); + assertEquals(0, m.start(0)); + assertEquals(5, m.end(0)); + assertEquals(0, m.start(1)); + assertEquals(2, m.end(1)); + assertEquals(3, m.start(2)); + assertEquals(5, m.end(2)); + assertEquals("p1#q3", m.group()); + assertEquals("p1#q3", m.group(0)); + assertEquals("p1", m.group(1)); + assertEquals("q3", m.group(2)); + + assertTrue(m.find()); + assertEquals(5, m.start()); + assertEquals(10, m.end()); + assertEquals(2, m.groupCount()); + assertEquals(10, m.end(0)); + assertEquals(5, m.start(1)); + assertEquals(7, m.end(1)); + assertEquals(7, m.start(2)); + assertEquals(10, m.end(2)); + assertEquals("p2q42", m.group()); + assertEquals("p2q42", m.group(0)); + assertEquals("p2", m.group(1)); + assertEquals("q42", m.group(2)); + + assertTrue(m.find()); + assertEquals(15, m.start()); + assertEquals(23, m.end()); + assertEquals(2, m.groupCount()); + assertEquals(15, m.start(0)); + assertEquals(23, m.end(0)); + assertEquals(15, m.start(1)); + assertEquals(18, m.end(1)); + assertEquals(19, m.start(2)); + assertEquals(23, m.end(2)); + assertEquals("p63#q888", m.group()); + assertEquals("p63#q888", m.group(0)); + assertEquals("p63", m.group(1)); + assertEquals("q888", m.group(2)); + assertFalse(m.find()); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies compile(String regex) method and matcher for created pattern.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies compile(String regex) method and matcher for created pattern.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testReplace() throws PatternSyntaxException { + Pattern p; + Matcher m; + + // Note: examples from book, + // Hitchens, Ron, 2002, "Java NIO", O'Reilly, page 171 + p = Pattern.compile("a*b"); + + m = p.matcher("aabfooaabfooabfoob"); + assertTrue(m.replaceAll("-").equals("-foo-foo-foo-")); + assertTrue(m.replaceFirst("-").equals("-fooaabfooabfoob")); + + /* + * p = Pattern.compile ("\\p{Blank}"); + * + * m = p.matcher ("fee fie foe fum"); assertTrue + * (m.replaceFirst("-").equals ("fee-fie foe fum")); assertTrue + * (m.replaceAll("-").equals ("fee-fie-foe-fum")); + */ + + p = Pattern.compile("([bB])yte"); + + m = p.matcher("Byte for byte"); + assertTrue(m.replaceFirst("$1ite").equals("Bite for byte")); + assertTrue(m.replaceAll("$1ite").equals("Bite for bite")); + + p = Pattern.compile("\\d\\d\\d\\d([- ])"); + + m = p.matcher("card #1234-5678-1234"); + assertTrue(m.replaceFirst("xxxx$1").equals("card #xxxx-5678-1234")); + assertTrue(m.replaceAll("xxxx$1").equals("card #xxxx-xxxx-1234")); + + p = Pattern.compile("(up|left)( *)(right|down)"); + + m = p.matcher("left right, up down"); + assertTrue(m.replaceFirst("$3$2$1").equals("right left, up down")); + assertTrue(m.replaceAll("$3$2$1").equals("right left, down up")); + + p = Pattern.compile("([CcPp][hl]e[ea]se)"); + + m = p.matcher("I want cheese. Please."); + assertTrue(m.replaceFirst("<b> $1 </b>").equals( + "I want <b> cheese </b>. Please.")); + assertTrue(m.replaceAll("<b> $1 </b>").equals( + "I want <b> cheese </b>. <b> Please </b>.")); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies compile(String regex) method and matcher for created pattern.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies compile(String regex) method and matcher for created pattern.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testEscapes() throws PatternSyntaxException { + Pattern p; + Matcher m; + + // Test \\ sequence + p = Pattern.compile("([a-z]+)\\\\([a-z]+);"); + m = p.matcher("fred\\ginger;abbott\\costello;jekell\\hyde;"); + assertTrue(m.find()); + assertEquals("fred", m.group(1)); + assertEquals("ginger", m.group(2)); + assertTrue(m.find()); + assertEquals("abbott", m.group(1)); + assertEquals("costello", m.group(2)); + assertTrue(m.find()); + assertEquals("jekell", m.group(1)); + assertEquals("hyde", m.group(2)); + assertFalse(m.find()); + + // Test \n, \t, \r, \f, \e, \a sequences + p = Pattern.compile("([a-z]+)[\\n\\t\\r\\f\\e\\a]+([a-z]+)"); + m = p.matcher("aa\nbb;cc\u0009\rdd;ee\u000C\u001Bff;gg\n\u0007hh"); + assertTrue(m.find()); + assertEquals("aa", m.group(1)); + assertEquals("bb", m.group(2)); + assertTrue(m.find()); + assertEquals("cc", m.group(1)); + assertEquals("dd", m.group(2)); + assertTrue(m.find()); + assertEquals("ee", m.group(1)); + assertEquals("ff", m.group(2)); + assertTrue(m.find()); + assertEquals("gg", m.group(1)); + assertEquals("hh", m.group(2)); + assertFalse(m.find()); + + // Test \\u and \\x sequences +/* p = Pattern.compile("([0-9]+)[\\u0020:\\x21];"); + m = p.matcher("11:;22 ;33-;44!;"); + assertTrue(m.find()); + assertEquals("11", m.group(1)); + assertTrue(m.find()); + assertEquals("22", m.group(1)); + assertTrue(m.find()); + assertEquals("44", m.group(1)); + assertFalse(m.find()); +*/ + // Test invalid unicode sequences +/* try { + p = Pattern.compile("\\u"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException e) { + } + + try { + p = Pattern.compile("\\u;"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException e) { + } + + try { + p = Pattern.compile("\\u002"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException e) { + } + + try { + p = Pattern.compile("\\u002;"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException e) { + } + + // Test invalid hex sequences + try { + p = Pattern.compile("\\x"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException e) { + } + + try { + p = Pattern.compile("\\x;"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException e) { + } + + try { + p = Pattern.compile("\\xa"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException e) { + } + + try { + p = Pattern.compile("\\xa;"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException e) { + } +*/ + // Test \0 (octal) sequences (1, 2 and 3 digit) + p = Pattern.compile("([0-9]+)[\\07\\040\\0160];"); + m = p.matcher("11\u0007;22:;33 ;44p;"); + assertTrue(m.find()); + assertEquals("11", m.group(1)); + assertTrue(m.find()); + assertEquals("33", m.group(1)); + assertTrue(m.find()); + assertEquals("44", m.group(1)); + assertFalse(m.find()); + + // Test invalid octal sequences + try { + p = Pattern.compile("\\08"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException e) { + } + + //originally contributed test did not check the result + //TODO: check what RI does here +// try { +// p = Pattern.compile("\\0477"); +// fail("PatternSyntaxException expected"); +// } catch (PatternSyntaxException e) { +// } + + try { + p = Pattern.compile("\\0"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException e) { + } + + try { + p = Pattern.compile("\\0;"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException e) { + } + + + // Test \c (control character) sequence + p = Pattern.compile("([0-9]+)[\\cA\\cB\\cC\\cD];"); + m = p.matcher("11\u0001;22:;33\u0002;44p;55\u0003;66\u0004;"); + assertTrue(m.find()); + assertEquals("11", m.group(1)); + assertTrue(m.find()); + assertEquals("33", m.group(1)); + assertTrue(m.find()); + assertEquals("55", m.group(1)); + assertTrue(m.find()); + assertEquals("66", m.group(1)); + assertFalse(m.find()); + + // More thorough control escape test + // Ensure that each escape matches exactly the corresponding + // character + // code and no others (well, from 0-255 at least) + int i, j; + for (i = 0; i < 26; i++) { + p = Pattern.compile("\\c" + Character.toString((char) ('A' + i))); + int match_char = -1; + for (j = 0; j < 255; j++) { + m = p.matcher(Character.toString((char) j)); + if (m.matches()) { + assertEquals(-1, match_char); + match_char = j; + } + } + assertTrue(match_char == i + 1); + } + + // Test invalid control escapes +// BEGIN android-removed +// ICU doesn't complain about illegal control sequences +// try { +// p = Pattern.compile("\\c"); +// fail("PatternSyntaxException expected"); +// } catch (PatternSyntaxException e) { +// } +// END android-removed + + //originally contributed test did not check the result + //TODO: check what RI does here +// try { +// p = Pattern.compile("\\c;"); +// fail("PatternSyntaxException expected"); +// } catch (PatternSyntaxException e) { +// } +// +// try { +// p = Pattern.compile("\\ca;"); +// fail("PatternSyntaxException expected"); +// } catch (PatternSyntaxException e) { +// } +// +// try { +// p = Pattern.compile("\\c4;"); +// fail("PatternSyntaxException expected"); +// } catch (PatternSyntaxException e) { +// } + } + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies patterns with different ranges of characters.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies patterns with different ranges of characters.", + method = "matcher", + args = {CharSequence.class} + ) + }) + public void testCharacterClasses() throws PatternSyntaxException { + Pattern p; + Matcher m; + + // Test one character range + p = Pattern.compile("[p].*[l]"); + m = p.matcher("paul"); + assertTrue(m.matches()); + m = p.matcher("pool"); + assertTrue(m.matches()); + m = p.matcher("pong"); + assertFalse(m.matches()); + m = p.matcher("pl"); + assertTrue(m.matches()); + + // Test two character range + p = Pattern.compile("[pm].*[lp]"); + m = p.matcher("prop"); + assertTrue(m.matches()); + m = p.matcher("mall"); + assertTrue(m.matches()); + m = p.matcher("pong"); + assertFalse(m.matches()); + m = p.matcher("pill"); + assertTrue(m.matches()); + + // Test range including [ and ] + p = Pattern.compile("[<\\[].*[\\]>]"); + m = p.matcher("<foo>"); + assertTrue(m.matches()); + m = p.matcher("[bar]"); + assertTrue(m.matches()); + m = p.matcher("{foobar]"); + assertFalse(m.matches()); + m = p.matcher("<pill]"); + assertTrue(m.matches()); + + // Test range using ^ + p = Pattern.compile("[^bc][a-z]+[tr]"); + m = p.matcher("pat"); + assertTrue(m.matches()); + m = p.matcher("liar"); + assertTrue(m.matches()); + m = p.matcher("car"); + assertFalse(m.matches()); + m = p.matcher("gnat"); + assertTrue(m.matches()); + + // Test character range using - + p = Pattern.compile("[a-z]_+[a-zA-Z]-+[0-9p-z]"); + m = p.matcher("d__F-8"); + assertTrue(m.matches()); + m = p.matcher("c_a-q"); + assertTrue(m.matches()); + m = p.matcher("a__R-a"); + assertFalse(m.matches()); + m = p.matcher("r_____d-----5"); + assertTrue(m.matches()); + + // Test range using unicode characters and unicode and hex escapes + p = Pattern.compile("[\\u1234-\\u2345]_+[a-z]-+[\u0001-\\x11]"); + m = p.matcher("\u2000_q-\u0007"); + assertTrue(m.matches()); + m = p.matcher("\u1234_z-\u0001"); + assertTrue(m.matches()); + m = p.matcher("r_p-q"); + assertFalse(m.matches()); + m = p.matcher("\u2345_____d-----\n"); + assertTrue(m.matches()); + +// BEGIN android-removed +// The "---" collides with ICU's "--" operator and is likely to be a user error +// anyway, so we simply comment this one out. +// // Test ranges including the "-" character +// p = Pattern.compile("[\\*-/]_+[---]!+[--AP]"); +// m = p.matcher("-_-!!A"); +// assertTrue(m.matches()); +// m = p.matcher("\u002b_-!!!-"); +// assertTrue(m.matches()); +// m = p.matcher("!_-!@"); +// assertFalse(m.matches()); +// m = p.matcher(",______-!!!!!!!P"); +// assertTrue(m.matches()); +// END android-removed + + // Test nested ranges + p = Pattern.compile("[pm[t]][a-z]+[[r]lp]"); + m = p.matcher("prop"); + assertTrue(m.matches()); + m = p.matcher("tsar"); + assertTrue(m.matches()); + m = p.matcher("pong"); + assertFalse(m.matches()); + m = p.matcher("moor"); + assertTrue(m.matches()); + + // Test character class intersection with && + // TODO: figure out what x&&y or any class with a null intersection + // set (like [[a-c]&&[d-f]]) might mean. It doesn't mean "match + // nothing" and doesn't mean "match anything" so I'm stumped. + p = Pattern.compile("[[a-p]&&[g-z]]+-+[[a-z]&&q]-+[x&&[a-z]]-+"); + m = p.matcher("h--q--x--"); + assertTrue(m.matches()); + m = p.matcher("hog--q-x-"); + assertTrue(m.matches()); + m = p.matcher("ape--q-x-"); + assertFalse(m.matches()); + m = p.matcher("mop--q-x----"); + assertTrue(m.matches()); + + // Test error cases with && +// BEGIN android-removed +// This is more of a bug, and ICU doesn't have this behavior. +// p = Pattern.compile("[&&[xyz]]"); +// m = p.matcher("&"); +// // System.out.println(m.matches()); +// m = p.matcher("x"); +// // System.out.println(m.matches()); +// m = p.matcher("y"); +// // System.out.println(m.matches()); +// END android-removed + p = Pattern.compile("[[xyz]&[axy]]"); + m = p.matcher("x"); + // System.out.println(m.matches()); + m = p.matcher("z"); + // System.out.println(m.matches()); + m = p.matcher("&"); + // System.out.println(m.matches()); + p = Pattern.compile("[abc[123]&&[345]def]"); + m = p.matcher("a"); + // System.out.println(m.matches()); + +// BEGIN android-removed +// This is more of a bug, and ICU doesn't have this behavior. +// p = Pattern.compile("[[xyz]&&]"); +// END android-removed + p = Pattern.compile("[[abc]&]"); + + try { + p = Pattern.compile("[[abc]&&"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException e) { + } + + p = Pattern.compile("[[abc]\\&&[xyz]]"); + + p = Pattern.compile("[[abc]&\\&[xyz]]"); + + // Test 3-way intersection + p = Pattern.compile("[[a-p]&&[g-z]&&[d-k]]"); + m = p.matcher("g"); + assertTrue(m.matches()); + m = p.matcher("m"); + assertFalse(m.matches()); + + // Test nested intersection + p = Pattern.compile("[[[a-p]&&[g-z]]&&[d-k]]"); + m = p.matcher("g"); + assertTrue(m.matches()); + m = p.matcher("m"); + assertFalse(m.matches()); + + // Test character class subtraction with && and ^ + p = Pattern.compile("[[a-z]&&[^aeiou]][aeiou][[^xyz]&&[a-z]]"); + m = p.matcher("pop"); + assertTrue(m.matches()); + m = p.matcher("tag"); + assertTrue(m.matches()); + m = p.matcher("eat"); + assertFalse(m.matches()); + m = p.matcher("tax"); + assertFalse(m.matches()); + m = p.matcher("zip"); + assertTrue(m.matches()); + + // Test . (DOT), with and without DOTALL + // Note: DOT not allowed in character classes + p = Pattern.compile(".+/x.z"); + m = p.matcher("!$/xyz"); + assertTrue(m.matches()); + m = p.matcher("%\n\r/x\nz"); + assertFalse(m.matches()); + p = Pattern.compile(".+/x.z", Pattern.DOTALL); + m = p.matcher("%\n\r/x\nz"); + assertTrue(m.matches()); + + // Test \d (digit) + p = Pattern.compile("\\d+[a-z][\\dx]"); + m = p.matcher("42a6"); + assertTrue(m.matches()); + m = p.matcher("21zx"); + assertTrue(m.matches()); + m = p.matcher("ab6"); + assertFalse(m.matches()); + m = p.matcher("56912f9"); + assertTrue(m.matches()); + + // Test \D (not a digit) + p = Pattern.compile("\\D+[a-z]-[\\D3]"); + m = p.matcher("za-p"); + assertTrue(m.matches()); + m = p.matcher("%!e-3"); + assertTrue(m.matches()); + m = p.matcher("9a-x"); + assertFalse(m.matches()); + m = p.matcher("\u1234pp\ny-3"); + assertTrue(m.matches()); + + // Test \s (whitespace) + p = Pattern.compile("<[a-zA-Z]+\\s+[0-9]+[\\sx][^\\s]>"); + m = p.matcher("<cat \t1\fx>"); + assertTrue(m.matches()); + m = p.matcher("<cat \t1\f >"); + assertFalse(m.matches()); + m = p + .matcher("xyz <foo\n\r22 5> <pp \t\n\f\r \u000b41x\u1234><pp \nx7\rc> zzz"); + assertTrue(m.find()); + assertTrue(m.find()); + assertFalse(m.find()); + + // Test \S (not whitespace) + p = Pattern.compile("<[a-z] \\S[0-9][\\S\n]+[^\\S]221>"); + m = p.matcher("<f $0**\n** 221>"); + assertTrue(m.matches()); + m = p.matcher("<x 441\t221>"); + assertTrue(m.matches()); + m = p.matcher("<z \t9\ng 221>"); + assertFalse(m.matches()); + m = p.matcher("<z 60\ngg\u1234\f221>"); + assertTrue(m.matches()); + p = Pattern.compile("<[a-z] \\S[0-9][\\S\n]+[^\\S]221[\\S&&[^abc]]>"); + m = p.matcher("<f $0**\n** 221x>"); + assertTrue(m.matches()); + m = p.matcher("<x 441\t221z>"); + assertTrue(m.matches()); + m = p.matcher("<x 441\t221 >"); + assertFalse(m.matches()); + m = p.matcher("<x 441\t221c>"); + assertFalse(m.matches()); + m = p.matcher("<z \t9\ng 221x>"); + assertFalse(m.matches()); + m = p.matcher("<z 60\ngg\u1234\f221\u0001>"); + assertTrue(m.matches()); + + // Test \w (ascii word) + p = Pattern.compile("<\\w+\\s[0-9]+;[^\\w]\\w+/[\\w$]+;"); + m = p.matcher("<f1 99;!foo5/a$7;"); + assertTrue(m.matches()); + m = p.matcher("<f$ 99;!foo5/a$7;"); + assertFalse(m.matches()); + m = p + .matcher("<abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789 99;!foo5/a$7;"); + assertTrue(m.matches()); + + // Test \W (not an ascii word) + p = Pattern.compile("<\\W\\w+\\s[0-9]+;[\\W_][^\\W]+\\s[0-9]+;"); + m = p.matcher("<$foo3\n99;_bar\t0;"); + assertTrue(m.matches()); + m = p.matcher("<hh 99;_g 0;"); + assertFalse(m.matches()); + m = p.matcher("<*xx\t00;^zz\f11;"); + assertTrue(m.matches()); + + // Test x|y pattern + // TODO + } + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies compile(String regex) method and matcher for patterns with POSIX characters.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies compile(String regex) method and matcher for patterns with POSIX characters.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testPOSIXGroups() throws PatternSyntaxException { + Pattern p; + Matcher m; + + // Test POSIX groups using \p and \P (in the group and not in the group) + // Groups are Lower, Upper, ASCII, Alpha, Digit, XDigit, Alnum, Punct, + // Graph, Print, Blank, Space, Cntrl + // Test \p{Lower} + /* + * FIXME: Requires complex range processing + * p = Pattern.compile("<\\p{Lower}\\d\\P{Lower}:[\\p{Lower}Z]\\s[^\\P{Lower}]>"); + * m = p.matcher("<a4P:g x>"); assertTrue(m.matches()); m = + * p.matcher("<p4%:Z\tq>"); assertTrue(m.matches()); m = + * p.matcher("<A6#:e e>"); assertFalse(m.matches()); + */ + p = Pattern.compile("\\p{Lower}+"); + m = p.matcher("abcdefghijklmnopqrstuvwxyz"); + assertTrue(m.matches()); + + // Invalid uses of \p{Lower} + try { + p = Pattern.compile("\\p"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException e) { + } + + try { + p = Pattern.compile("\\p;"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException e) { + } + + try { + p = Pattern.compile("\\p{"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException e) { + } + + try { + p = Pattern.compile("\\p{;"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException e) { + } + + try { + p = Pattern.compile("\\p{Lower"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException e) { + } + + try { + p = Pattern.compile("\\p{Lower;"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException e) { + } + + // Test \p{Upper} + /* + * FIXME: Requires complex range processing + * p = Pattern.compile("<\\p{Upper}\\d\\P{Upper}:[\\p{Upper}z]\\s[^\\P{Upper}]>"); + * m = p.matcher("<A4p:G X>"); assertTrue(m.matches()); m = + * p.matcher("<P4%:z\tQ>"); assertTrue(m.matches()); m = + * p.matcher("<a6#:E E>"); assertFalse(m.matches()); + */ + p = Pattern.compile("\\p{Upper}+"); + m = p.matcher("ABCDEFGHIJKLMNOPQRSTUVWXYZ"); + assertTrue(m.matches()); + + // Invalid uses of \p{Upper} + try { + p = Pattern.compile("\\p{Upper"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException e) { + } + + try { + p = Pattern.compile("\\p{Upper;"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException e) { + } + + // Test \p{ASCII} + /* + * FIXME: Requires complex range processing p = Pattern.compile("<\\p{ASCII}\\d\\P{ASCII}:[\\p{ASCII}\u1234]\\s[^\\P{ASCII}]>"); + * m = p.matcher("<A4\u0080:G X>"); assertTrue(m.matches()); m = + * p.matcher("<P4\u00ff:\u1234\t\n>"); assertTrue(m.matches()); m = + * p.matcher("<\u00846#:E E>"); assertFalse(m.matches()) + */ + int i; + p = Pattern.compile("\\p{ASCII}"); + for (i = 0; i < 0x80; i++) { + m = p.matcher(Character.toString((char) i)); + assertTrue(m.matches()); + } + for (; i < 0xff; i++) { + m = p.matcher(Character.toString((char) i)); + assertFalse(m.matches()); + } + + // Invalid uses of \p{ASCII} + try { + p = Pattern.compile("\\p{ASCII"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException e) { + } + + try { + p = Pattern.compile("\\p{ASCII;"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException e) { + } + + // Test \p{Alpha} + // TODO + + // Test \p{Digit} + // TODO + + // Test \p{XDigit} + // TODO + + // Test \p{Alnum} + // TODO + + // Test \p{Punct} + // TODO + + // Test \p{Graph} + // TODO + + // Test \p{Print} + // TODO + + // Test \p{Blank} + // TODO + + // Test \p{Space} + // TODO + + // Test \p{Cntrl} + // TODO + } + @TestTargetNew( + level = TestLevel.ADDITIONAL, + notes = "TODO empty test", + method = "!", + args = {} + ) + @BrokenTest("empty test") + public void testUnicodeCategories() throws PatternSyntaxException { + // Test Unicode categories using \p and \P + // One letter codes: L, M, N, P, S, Z, C + // Two letter codes: Lu, Nd, Sc, Sm, ... + // See java.lang.Character and Unicode standard for complete list + // TODO + // Test \p{L} + // TODO + + // Test \p{N} + // TODO + + // ... etc + + // Test two letter codes: + // From unicode.org: + // Lu + // Ll + // Lt + // Lm + // Lo + // Mn + // Mc + // Me + // Nd + // Nl + // No + // Pc + // Pd + // Ps + // Pe + // Pi + // Pf + // Po + // Sm + // Sc + // Sk + // So + // Zs + // Zl + // Zp + // Cc + // Cf + // Cs + // Co + // Cn + } + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies matcher(CharSequence input) method for input specified by Unicode blocks.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + public void testUnicodeBlocks() throws PatternSyntaxException { + Pattern p; + Matcher m; + int i, j; + + // Test Unicode blocks using \p and \P + // FIXME: + // Note that LatinExtended-B and ArabicPresentations-B are unrecognized + // by the reference JDK. + for (i = 0; i < UBlocks.length; i++) { + /* + * p = Pattern.compile("\\p{"+UBlocks[i].name+"}"); + * + * if (UBlocks[i].low > 0) { m = + * p.matcher(Character.toString((char)(UBlocks[i].low-1))); + * assertFalse(m.matches()); } for (j=UBlocks[i].low; j <= + * UBlocks[i].high; j++) { m = + * p.matcher(Character.toString((char)j)); + * assertTrue(m.matches()); } if (UBlocks[i].high < 0xFFFF) { m = + * p.matcher(Character.toString((char)(UBlocks[i].high+1))); + * assertFalse(m.matches()); } + * + * p = Pattern.compile("\\P{"+UBlocks[i].name+"}"); + * + * if (UBlocks[i].low > 0) { m = + * p.matcher(Character.toString((char)(UBlocks[i].low-1))); + * assertTrue(m.matches()); } for (j=UBlocks[i].low; j < + * UBlocks[i].high; j++) { m = + * p.matcher(Character.toString((char)j)); + * assertFalse(m.matches()); } if (UBlocks[i].high < 0xFFFF) { m = + * p.matcher(Character.toString((char)(UBlocks[i].high+1))); + * assertTrue(m.matches()); } + */ + + p = Pattern.compile("\\p{In" + UBlocks[i].name + "}"); +// BEGIN android-changed +// Added the name of the block under test to the assertion to get more output. + + if (UBlocks[i].low > 0) { + m = p.matcher(Character.toString((char) (UBlocks[i].low - 1))); + assertFalse(UBlocks[i].name, m.matches()); + } + for (j = UBlocks[i].low; j <= UBlocks[i].high; j++) { + m = p.matcher(Character.toString((char) j)); + assertTrue(UBlocks[i].name, m.matches()); + } + if (UBlocks[i].high < 0xFFFF) { + m = p.matcher(Character.toString((char) (UBlocks[i].high + 1))); + assertFalse(UBlocks[i].name, m.matches()); + } + + p = Pattern.compile("\\P{In" + UBlocks[i].name + "}"); + + if (UBlocks[i].low > 0) { + m = p.matcher(Character.toString((char) (UBlocks[i].low - 1))); + assertTrue(UBlocks[i].name, m.matches()); + } + for (j = UBlocks[i].low; j < UBlocks[i].high; j++) { + m = p.matcher(Character.toString((char) j)); + assertFalse(UBlocks[i].name, m.matches()); + } + if (UBlocks[i].high < 0xFFFF) { + m = p.matcher(Character.toString((char) (UBlocks[i].high + 1))); + assertTrue(UBlocks[i].name, m.matches()); + } + +// END android-changed + } + } + @TestTargetNew( + level = TestLevel.ADDITIONAL, + notes = "TODO empty test", + method = "!", + args = {} + ) + @BrokenTest("empty test") + public void testCapturingGroups() throws PatternSyntaxException { + // Test simple capturing groups + // TODO + + // Test grouping without capture (?:...) + // TODO + + // Test combination of grouping and capture + // TODO + + // Test \<num> sequence with capturing and non-capturing groups + // TODO + + // Test \<num> with <num> out of range + // TODO + } + @TestTargetNew( + level = TestLevel.ADDITIONAL, + notes = "TODO empty test", + method = "!", + args = {} + ) + @BrokenTest("empty test") + public void testRepeats() { + // Test ? + // TODO + + // Test * + // TODO + + // Test + + // TODO + + // Test {<num>}, including 0, 1 and more + // TODO + + // Test {<num>,}, including 0, 1 and more + // TODO + + // Test {<n1>,<n2>}, with n1 < n2, n1 = n2 and n1 > n2 (illegal?) + // TODO + } + @TestTargetNew( + level = TestLevel.ADDITIONAL, + notes = "TODO empty test", + method = "!", + args = {} + ) + @BrokenTest("empty test") + public void testAnchors() throws PatternSyntaxException { + // Test ^, default and MULTILINE + // TODO + + // Test $, default and MULTILINE + // TODO + + // Test \b (word boundary) + // TODO + + // Test \B (not a word boundary) + // TODO + + // Test \A (beginning of string) + // TODO + + // Test \Z (end of string) + // TODO + + // Test \z (end of string) + // TODO + + // Test \G + // TODO + + // Test positive lookahead using (?=...) + // TODO + + // Test negative lookahead using (?!...) + // TODO + + // Test positive lookbehind using (?<=...) + // TODO + + // Test negative lookbehind using (?<!...) + // TODO + } + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies compile(String regex) method and matcher for created pattern.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies compile(String regex) method and matcher for created pattern.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testMisc() throws PatternSyntaxException { + Pattern p; + Matcher m; + + // Test (?>...) + // TODO + + // Test (?onflags-offflags) + // Valid flags are i,m,d,s,u,x + // TODO + + // Test (?onflags-offflags:...) + // TODO + + // Test \Q, \E + p = Pattern.compile("[a-z]+;\\Q[a-z]+;\\Q(foo.*);\\E[0-9]+"); + m = p.matcher("abc;[a-z]+;\\Q(foo.*);411"); + assertTrue(m.matches()); + m = p.matcher("abc;def;foo42;555"); + assertFalse(m.matches()); + m = p.matcher("abc;\\Qdef;\\Qfoo99;\\E123"); + assertFalse(m.matches()); + + p = Pattern.compile("[a-z]+;(foo[0-9]-\\Q(...)\\E);[0-9]+"); + m = p.matcher("abc;foo5-(...);123"); + assertTrue(m.matches()); + assertEquals("foo5-(...)", m.group(1)); + m = p.matcher("abc;foo9-(xxx);789"); + assertFalse(m.matches()); + + p = Pattern.compile("[a-z]+;(bar[0-9]-[a-z\\Q$-\\E]+);[0-9]+"); + m = p.matcher("abc;bar0-def$-;123"); + assertTrue(m.matches()); + + // FIXME: + // This should work the same as the pattern above but fails with the + // the reference JDK + p = Pattern.compile("[a-z]+;(bar[0-9]-[a-z\\Q-$\\E]+);[0-9]+"); + m = p.matcher("abc;bar0-def$-;123"); + // assertTrue(m.matches()); + + // FIXME: + // This should work too .. it looks as if just about anything that + // has more + // than one character between \Q and \E is broken in the the reference JDK + p = Pattern.compile("[a-z]+;(bar[0-9]-[a-z\\Q[0-9]\\E]+);[0-9]+"); + m = p.matcher("abc;bar0-def[99]-]0x[;123"); + // assertTrue(m.matches()); + + // This is the same as above but with explicit escapes .. and this + // does work + // on the the reference JDK + p = Pattern.compile("[a-z]+;(bar[0-9]-[a-z\\[0\\-9\\]]+);[0-9]+"); + m = p.matcher("abc;bar0-def[99]-]0x[;123"); + assertTrue(m.matches()); + + // Test #<comment text> + // TODO + } + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies compile(String regex) method.", + method = "compile", + args = {java.lang.String.class} + ) + public void testCompile1() throws PatternSyntaxException { + Pattern pattern = Pattern + .compile("[0-9A-Za-z][0-9A-Za-z\\x2e\\x3a\\x2d\\x5f]*"); + String name = "iso-8859-1"; + assertTrue(pattern.matcher(name).matches()); + } + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies compile(String regex, int flag) method.", + method = "compile", + args = {java.lang.String.class, int.class} + ) + public void testCompile2() throws PatternSyntaxException { + String findString = "\\Qimport\\E"; + + Pattern pattern = Pattern.compile(findString, 0); + Matcher matcher = pattern.matcher(new String( + "import a.A;\n\n import b.B;\nclass C {}")); + + assertTrue(matcher.find(0)); + } + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies compile(String regex) and compile(String regex, int flag) method for specific patterns.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies compile(String regex) and compile(String regex, int flag) method for specific patterns.", + method = "compile", + args = {java.lang.String.class, int.class} + ) + }) + public void testCompile3() throws PatternSyntaxException { + Pattern p; + Matcher m; + p = Pattern.compile("a$"); + m = p.matcher("a\n"); + assertTrue(m.find()); + assertEquals("a", m.group()); + assertFalse(m.find()); + + p = Pattern.compile("(a$)"); + m = p.matcher("a\n"); + assertTrue(m.find()); + assertEquals("a", m.group()); + assertEquals("a", m.group(1)); + assertFalse(m.find()); + + p = Pattern.compile("^.*$", Pattern.MULTILINE); + + m = p.matcher("a\n"); + assertTrue(m.find()); + // System.out.println("["+m.group()+"]"); + assertEquals("a", m.group()); + assertFalse(m.find()); + + m = p.matcher("a\nb\n"); + assertTrue(m.find()); + // System.out.println("["+m.group()+"]"); + assertEquals("a", m.group()); + assertTrue(m.find()); + // System.out.println("["+m.group()+"]"); + assertEquals("b", m.group()); + assertFalse(m.find()); + + m = p.matcher("a\nb"); + assertTrue(m.find()); + // System.out.println("["+m.group()+"]"); + assertEquals("a", m.group()); + assertTrue(m.find()); + assertEquals("b", m.group()); + assertFalse(m.find()); + + m = p.matcher("\naa\r\nbb\rcc\n\n"); + assertTrue(m.find()); + // System.out.println("["+m.group()+"]"); + assertTrue(m.group().equals("")); + assertTrue(m.find()); + // System.out.println("["+m.group()+"]"); + assertEquals("aa", m.group()); + assertTrue(m.find()); + // System.out.println("["+m.group()+"]"); + assertEquals("bb", m.group()); + assertTrue(m.find()); + // System.out.println("["+m.group()+"]"); + assertEquals("cc", m.group()); + assertTrue(m.find()); + // System.out.println("["+m.group()+"]"); + assertTrue(m.group().equals("")); + assertFalse(m.find()); + + m = p.matcher("a"); + assertTrue(m.find()); + assertEquals("a", m.group()); + assertFalse(m.find()); + +// BEGIN android-removed +// Makes no sense to duplicate this weird behavior +// m = p.matcher(""); +// // FIXME: This matches the reference behaviour but is +// // inconsistent with matching "a" - ie. the end of the +// // target string should match against $ always but this +// // appears to work with the null string only when not in +// // multiline mode (see below) +// assertFalse(m.find()); +// END android-removed + + p = Pattern.compile("^.*$"); + m = p.matcher(""); + assertTrue(m.find()); + assertTrue(m.group().equals("")); + assertFalse(m.find()); + } + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies compile(String regex, int flag) method for specific string.", + method = "compile", + args = {java.lang.String.class, int.class} + ) + public void testCompile4() throws PatternSyntaxException { + String findString = "\\Qpublic\\E"; + StringBuffer text = new StringBuffer(" public class Class {\n" + + " public class Class {"); + + Pattern pattern = Pattern.compile(findString, 0); + Matcher matcher = pattern.matcher(text); + + boolean found = matcher.find(); + assertTrue(found); + assertEquals(4, matcher.start()); + if (found) { + // modify text + text.delete(0, text.length()); + text.append("Text have been changed."); + matcher.reset(text); + } + + found = matcher.find(); + assertFalse(found); + } + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies compile(String regex) methodfor specific string.", + method = "compile", + args = {java.lang.String.class} + ) + public void testCompile5() throws PatternSyntaxException { + Pattern p = Pattern.compile("^[0-9]"); + String s[] = p.split("12", -1); + assertEquals("", s[0]); + assertEquals("2", s[1]); + assertEquals(2, s.length); + } + + // public void testCompile6() { + // String regex = "[\\p{L}[\\p{Mn}[\\p{Pc}[\\p{Nd}[\\p{Nl}[\\p{Sc}]]]]]]+"; + // String regex = "[\\p{L}\\p{Mn}\\p{Pc}\\p{Nd}\\p{Nl}\\p{Sc}]+"; + // try { + // Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE); + // assertTrue(true); + // } catch (PatternSyntaxException e) { + // System.out.println(e.getMessage()); + // assertTrue(false); + // } + // } + + private static class UBInfo { + public UBInfo(int low, int high, String name) { + this.name = name; + this.low = low; + this.high = high; + } + + public String name; + + public int low, high; + } + + // A table representing the unicode categories + //private static UBInfo[] UCategories = { + // Lu + // Ll + // Lt + // Lm + // Lo + // Mn + // Mc + // Me + // Nd + // Nl + // No + // Pc + // Pd + // Ps + // Pe + // Pi + // Pf + // Po + // Sm + // Sc + // Sk + // So + // Zs + // Zl + // Zp + // Cc + // Cf + // Cs + // Co + // Cn + //}; + + // A table representing the unicode character blocks + private static UBInfo[] UBlocks = { + /* 0000; 007F; Basic Latin */ + new UBInfo(0x0000, 0x007F, "BasicLatin"), // Character.UnicodeBlock.BASIC_LATIN + /* 0080; 00FF; Latin-1 Supplement */ + new UBInfo(0x0080, 0x00FF, "Latin-1Supplement"), // Character.UnicodeBlock.LATIN_1_SUPPLEMENT + /* 0100; 017F; Latin Extended-A */ + new UBInfo(0x0100, 0x017F, "LatinExtended-A"), // Character.UnicodeBlock.LATIN_EXTENDED_A + /* 0180; 024F; Latin Extended-B */ + // new UBInfo (0x0180,0x024F,"InLatinExtended-B"), // + // Character.UnicodeBlock.LATIN_EXTENDED_B + /* 0250; 02AF; IPA Extensions */ + new UBInfo(0x0250, 0x02AF, "IPAExtensions"), // Character.UnicodeBlock.IPA_EXTENSIONS + /* 02B0; 02FF; Spacing Modifier Letters */ + new UBInfo(0x02B0, 0x02FF, "SpacingModifierLetters"), // Character.UnicodeBlock.SPACING_MODIFIER_LETTERS + /* 0300; 036F; Combining Diacritical Marks */ + new UBInfo(0x0300, 0x036F, "CombiningDiacriticalMarks"), // Character.UnicodeBlock.COMBINING_DIACRITICAL_MARKS + /* 0370; 03FF; Greek */ + new UBInfo(0x0370, 0x03FF, "Greek"), // Character.UnicodeBlock.GREEK + /* 0400; 04FF; Cyrillic */ + new UBInfo(0x0400, 0x04FF, "Cyrillic"), // Character.UnicodeBlock.CYRILLIC + /* 0530; 058F; Armenian */ + new UBInfo(0x0530, 0x058F, "Armenian"), // Character.UnicodeBlock.ARMENIAN + /* 0590; 05FF; Hebrew */ + new UBInfo(0x0590, 0x05FF, "Hebrew"), // Character.UnicodeBlock.HEBREW + /* 0600; 06FF; Arabic */ + new UBInfo(0x0600, 0x06FF, "Arabic"), // Character.UnicodeBlock.ARABIC + /* 0700; 074F; Syriac */ + new UBInfo(0x0700, 0x074F, "Syriac"), // Character.UnicodeBlock.SYRIAC + /* 0780; 07BF; Thaana */ + new UBInfo(0x0780, 0x07BF, "Thaana"), // Character.UnicodeBlock.THAANA + /* 0900; 097F; Devanagari */ + new UBInfo(0x0900, 0x097F, "Devanagari"), // Character.UnicodeBlock.DEVANAGARI + /* 0980; 09FF; Bengali */ + new UBInfo(0x0980, 0x09FF, "Bengali"), // Character.UnicodeBlock.BENGALI + /* 0A00; 0A7F; Gurmukhi */ + new UBInfo(0x0A00, 0x0A7F, "Gurmukhi"), // Character.UnicodeBlock.GURMUKHI + /* 0A80; 0AFF; Gujarati */ + new UBInfo(0x0A80, 0x0AFF, "Gujarati"), // Character.UnicodeBlock.GUJARATI + /* 0B00; 0B7F; Oriya */ + new UBInfo(0x0B00, 0x0B7F, "Oriya"), // Character.UnicodeBlock.ORIYA + /* 0B80; 0BFF; Tamil */ + new UBInfo(0x0B80, 0x0BFF, "Tamil"), // Character.UnicodeBlock.TAMIL + /* 0C00; 0C7F; Telugu */ + new UBInfo(0x0C00, 0x0C7F, "Telugu"), // Character.UnicodeBlock.TELUGU + /* 0C80; 0CFF; Kannada */ + new UBInfo(0x0C80, 0x0CFF, "Kannada"), // Character.UnicodeBlock.KANNADA + /* 0D00; 0D7F; Malayalam */ + new UBInfo(0x0D00, 0x0D7F, "Malayalam"), // Character.UnicodeBlock.MALAYALAM + /* 0D80; 0DFF; Sinhala */ + new UBInfo(0x0D80, 0x0DFF, "Sinhala"), // Character.UnicodeBlock.SINHALA + /* 0E00; 0E7F; Thai */ + new UBInfo(0x0E00, 0x0E7F, "Thai"), // Character.UnicodeBlock.THAI + /* 0E80; 0EFF; Lao */ + new UBInfo(0x0E80, 0x0EFF, "Lao"), // Character.UnicodeBlock.LAO + /* 0F00; 0FFF; Tibetan */ + new UBInfo(0x0F00, 0x0FFF, "Tibetan"), // Character.UnicodeBlock.TIBETAN + /* 1000; 109F; Myanmar */ + new UBInfo(0x1000, 0x109F, "Myanmar"), // Character.UnicodeBlock.MYANMAR + /* 10A0; 10FF; Georgian */ + new UBInfo(0x10A0, 0x10FF, "Georgian"), // Character.UnicodeBlock.GEORGIAN + /* 1100; 11FF; Hangul Jamo */ + new UBInfo(0x1100, 0x11FF, "HangulJamo"), // Character.UnicodeBlock.HANGUL_JAMO + /* 1200; 137F; Ethiopic */ + new UBInfo(0x1200, 0x137F, "Ethiopic"), // Character.UnicodeBlock.ETHIOPIC + /* 13A0; 13FF; Cherokee */ + new UBInfo(0x13A0, 0x13FF, "Cherokee"), // Character.UnicodeBlock.CHEROKEE + /* 1400; 167F; Unified Canadian Aboriginal Syllabics */ + new UBInfo(0x1400, 0x167F, "UnifiedCanadianAboriginalSyllabics"), // Character.UnicodeBlock.UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS + /* 1680; 169F; Ogham */ + new UBInfo(0x1680, 0x169F, "Ogham"), // Character.UnicodeBlock.OGHAM + /* 16A0; 16FF; Runic */ + new UBInfo(0x16A0, 0x16FF, "Runic"), // Character.UnicodeBlock.RUNIC + /* 1780; 17FF; Khmer */ + new UBInfo(0x1780, 0x17FF, "Khmer"), // Character.UnicodeBlock.KHMER + /* 1800; 18AF; Mongolian */ + new UBInfo(0x1800, 0x18AF, "Mongolian"), // Character.UnicodeBlock.MONGOLIAN + /* 1E00; 1EFF; Latin Extended Additional */ + new UBInfo(0x1E00, 0x1EFF, "LatinExtendedAdditional"), // Character.UnicodeBlock.LATIN_EXTENDED_ADDITIONAL + /* 1F00; 1FFF; Greek Extended */ + new UBInfo(0x1F00, 0x1FFF, "GreekExtended"), // Character.UnicodeBlock.GREEK_EXTENDED + /* 2000; 206F; General Punctuation */ + new UBInfo(0x2000, 0x206F, "GeneralPunctuation"), // Character.UnicodeBlock.GENERAL_PUNCTUATION + /* 2070; 209F; Superscripts and Subscripts */ + new UBInfo(0x2070, 0x209F, "SuperscriptsandSubscripts"), // Character.UnicodeBlock.SUPERSCRIPTS_AND_SUBSCRIPTS + /* 20A0; 20CF; Currency Symbols */ + new UBInfo(0x20A0, 0x20CF, "CurrencySymbols"), // Character.UnicodeBlock.CURRENCY_SYMBOLS + /* 20D0; 20FF; Combining Marks for Symbols */ + new UBInfo(0x20D0, 0x20FF, "CombiningMarksforSymbols"), // Character.UnicodeBlock.COMBINING_MARKS_FOR_SYMBOLS + /* 2100; 214F; Letterlike Symbols */ + new UBInfo(0x2100, 0x214F, "LetterlikeSymbols"), // Character.UnicodeBlock.LETTERLIKE_SYMBOLS + /* 2150; 218F; Number Forms */ + new UBInfo(0x2150, 0x218F, "NumberForms"), // Character.UnicodeBlock.NUMBER_FORMS + /* 2190; 21FF; Arrows */ + new UBInfo(0x2190, 0x21FF, "Arrows"), // Character.UnicodeBlock.ARROWS + /* 2200; 22FF; Mathematical Operators */ + new UBInfo(0x2200, 0x22FF, "MathematicalOperators"), // Character.UnicodeBlock.MATHEMATICAL_OPERATORS + /* 2300; 23FF; Miscellaneous Technical */ + new UBInfo(0x2300, 0x23FF, "MiscellaneousTechnical"), // Character.UnicodeBlock.MISCELLANEOUS_TECHNICAL + /* 2400; 243F; Control Pictures */ + new UBInfo(0x2400, 0x243F, "ControlPictures"), // Character.UnicodeBlock.CONTROL_PICTURES + /* 2440; 245F; Optical Character Recognition */ + new UBInfo(0x2440, 0x245F, "OpticalCharacterRecognition"), // Character.UnicodeBlock.OPTICAL_CHARACTER_RECOGNITION + /* 2460; 24FF; Enclosed Alphanumerics */ + new UBInfo(0x2460, 0x24FF, "EnclosedAlphanumerics"), // Character.UnicodeBlock.ENCLOSED_ALPHANUMERICS + /* 2500; 257F; Box Drawing */ + new UBInfo(0x2500, 0x257F, "BoxDrawing"), // Character.UnicodeBlock.BOX_DRAWING + /* 2580; 259F; Block Elements */ + new UBInfo(0x2580, 0x259F, "BlockElements"), // Character.UnicodeBlock.BLOCK_ELEMENTS + /* 25A0; 25FF; Geometric Shapes */ + new UBInfo(0x25A0, 0x25FF, "GeometricShapes"), // Character.UnicodeBlock.GEOMETRIC_SHAPES + /* 2600; 26FF; Miscellaneous Symbols */ + new UBInfo(0x2600, 0x26FF, "MiscellaneousSymbols"), // Character.UnicodeBlock.MISCELLANEOUS_SYMBOLS + /* 2700; 27BF; Dingbats */ + new UBInfo(0x2700, 0x27BF, "Dingbats"), // Character.UnicodeBlock.DINGBATS + /* 2800; 28FF; Braille Patterns */ + new UBInfo(0x2800, 0x28FF, "BraillePatterns"), // Character.UnicodeBlock.BRAILLE_PATTERNS + /* 2E80; 2EFF; CJK Radicals Supplement */ + new UBInfo(0x2E80, 0x2EFF, "CJKRadicalsSupplement"), // Character.UnicodeBlock.CJK_RADICALS_SUPPLEMENT + /* 2F00; 2FDF; Kangxi Radicals */ + new UBInfo(0x2F00, 0x2FDF, "KangxiRadicals"), // Character.UnicodeBlock.KANGXI_RADICALS + /* 2FF0; 2FFF; Ideographic Description Characters */ + new UBInfo(0x2FF0, 0x2FFF, "IdeographicDescriptionCharacters"), // Character.UnicodeBlock.IDEOGRAPHIC_DESCRIPTION_CHARACTERS + /* 3000; 303F; CJK Symbols and Punctuation */ + new UBInfo(0x3000, 0x303F, "CJKSymbolsandPunctuation"), // Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION + /* 3040; 309F; Hiragana */ + new UBInfo(0x3040, 0x309F, "Hiragana"), // Character.UnicodeBlock.HIRAGANA + /* 30A0; 30FF; Katakana */ + new UBInfo(0x30A0, 0x30FF, "Katakana"), // Character.UnicodeBlock.KATAKANA + /* 3100; 312F; Bopomofo */ + new UBInfo(0x3100, 0x312F, "Bopomofo"), // Character.UnicodeBlock.BOPOMOFO + /* 3130; 318F; Hangul Compatibility Jamo */ + new UBInfo(0x3130, 0x318F, "HangulCompatibilityJamo"), // Character.UnicodeBlock.HANGUL_COMPATIBILITY_JAMO + /* 3190; 319F; Kanbun */ + new UBInfo(0x3190, 0x319F, "Kanbun"), // Character.UnicodeBlock.KANBUN + /* 31A0; 31BF; Bopomofo Extended */ + new UBInfo(0x31A0, 0x31BF, "BopomofoExtended"), // Character.UnicodeBlock.BOPOMOFO_EXTENDED + /* 3200; 32FF; Enclosed CJK Letters and Months */ + new UBInfo(0x3200, 0x32FF, "EnclosedCJKLettersandMonths"), // Character.UnicodeBlock.ENCLOSED_CJK_LETTERS_AND_MONTHS + /* 3300; 33FF; CJK Compatibility */ + new UBInfo(0x3300, 0x33FF, "CJKCompatibility"), // Character.UnicodeBlock.CJK_COMPATIBILITY + /* 3400; 4DB5; CJK Unified Ideographs Extension A */ +// BEGIN android-changed +// Modified this to reflect current Unicode tables (or maybe it was a typo) + new UBInfo(0x3400, 0x4DBF, "CJKUnifiedIdeographsExtensionA"), // Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A +// END android-changed + /* 4E00; 9FFF; CJK Unified Ideographs */ + new UBInfo(0x4E00, 0x9FFF, "CJKUnifiedIdeographs"), // Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS + /* A000; A48F; Yi Syllables */ + new UBInfo(0xA000, 0xA48F, "YiSyllables"), // Character.UnicodeBlock.YI_SYLLABLES + /* A490; A4CF; Yi Radicals */ + new UBInfo(0xA490, 0xA4CF, "YiRadicals"), // Character.UnicodeBlock.YI_RADICALS + /* AC00; D7A3; Hangul Syllables */ +// BEGIN android-changed +// Modified this to reflect current Unicode tables (or maybe it was a typo) + new UBInfo(0xAC00, 0xD7AF, "HangulSyllables"), // Character.UnicodeBlock.HANGUL_SYLLABLES +// END android-changed + /* D800; DB7F; High Surrogates */ + /* DB80; DBFF; High Private Use Surrogates */ + /* DC00; DFFF; Low Surrogates */ + /* E000; F8FF; Private Use */ + /* F900; FAFF; CJK Compatibility Ideographs */ + new UBInfo(0xF900, 0xFAFF, "CJKCompatibilityIdeographs"), // Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS + /* FB00; FB4F; Alphabetic Presentation Forms */ + new UBInfo(0xFB00, 0xFB4F, "AlphabeticPresentationForms"), // Character.UnicodeBlock.ALPHABETIC_PRESENTATION_FORMS + /* FB50; FDFF; Arabic Presentation Forms-A */ + new UBInfo(0xFB50, 0xFDFF, "ArabicPresentationForms-A"), // Character.UnicodeBlock.ARABIC_PRESENTATION_FORMS_A + /* FE20; FE2F; Combining Half Marks */ + new UBInfo(0xFE20, 0xFE2F, "CombiningHalfMarks"), // Character.UnicodeBlock.COMBINING_HALF_MARKS + /* FE30; FE4F; CJK Compatibility Forms */ + new UBInfo(0xFE30, 0xFE4F, "CJKCompatibilityForms"), // Character.UnicodeBlock.CJK_COMPATIBILITY_FORMS + /* FE50; FE6F; Small Form Variants */ + new UBInfo(0xFE50, 0xFE6F, "SmallFormVariants"), // Character.UnicodeBlock.SMALL_FORM_VARIANTS + /* FE70; FEFE; Arabic Presentation Forms-B */ + // new UBInfo (0xFE70,0xFEFE,"InArabicPresentationForms-B"), // + // Character.UnicodeBlock.ARABIC_PRESENTATION_FORMS_B + /* FEFF; FEFF; Specials */ +// BEGIN android-changed +// Modified this to reflect current Unicode tables (or maybe it was a typo) +// FEFF is actually still Arabic Presentation Forms B +// new UBInfo(0xFEFF, 0xFEFF, "Specials"), // Character.UnicodeBlock.SPECIALS +// END android-changed + /* FF00; FFEF; Halfwidth and Fullwidth Forms */ + new UBInfo(0xFF00, 0xFFEF, "HalfwidthandFullwidthForms"), // Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS + /* FFF0; FFFD; Specials */ + // BEGIN android-changed +// Modified this to reflect current Unicode tables (or maybe it was a typo) + new UBInfo(0xFFF0, 0xFFFF, "Specials") // Character.UnicodeBlock.SPECIALS +// END android-changed + }; +}
\ No newline at end of file diff --git a/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/PatternErrorTest.java b/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/PatternErrorTest.java new file mode 100644 index 0000000..a9b782b --- /dev/null +++ b/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/PatternErrorTest.java @@ -0,0 +1,103 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.harmony.regex.tests.java.util.regex; + +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestLevel; + +import java.util.regex.Pattern; +import junit.framework.TestCase; + +@TestTargetClass(Pattern.class) +/** + * Test boundary and error conditions in java.util.regex.Pattern + * + */ +public class PatternErrorTest extends TestCase { + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies compile(String regex) and compile(String regex, int flag) method with invalid parameters. Doesn't verify IllegalArgumentException, PatternSyntaxException.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies compile(String regex) and compile(String regex, int flag) method with invalid parameters. Doesn't verify IllegalArgumentException, PatternSyntaxException.", + method = "compile", + args = {java.lang.String.class, int.class} + ) + }) + public void testCompileErrors() throws Exception { + // null regex string - should get NullPointerException + try { + Pattern.compile(null); + fail("NullPointerException expected"); + } catch (NullPointerException e) { + } + + + // empty regex string - no exception should be thrown + Pattern.compile(""); + + // note: invalid regex syntax checked in PatternSyntaxExceptionTest + + // flags = 0 should raise no exception + int flags = 0; + Pattern.compile("foo", flags); + + // check that all valid flags accepted without exception + flags |= Pattern.UNIX_LINES; + flags |= Pattern.CASE_INSENSITIVE; + flags |= Pattern.MULTILINE; + // BEGIN android-changed + // We don't support that flag. + // flags |= Pattern.CANON_EQ; + // END android-changed + flags |= Pattern.COMMENTS; + flags |= Pattern.DOTALL; + flags |= Pattern.UNICODE_CASE; + Pattern.compile("foo", flags); + + // add invalid flags - should get IllegalArgumentException + /* + * TODO: Inconsistency between the reference JDK behaviour and spec - exception is + * not thrown + */ + /* + * Valid test is: + * flags |= 0xFFFFFFFF; + * try { + * Pattern.compile("foo",flags); + * } catch (IllegalArgumentException e) { + * // This is the expected exception + * } catch (Exception e) { + * fail(); + * } + */ + + /* Workaround test is: */ + // BEGIN android-changed + // We don't support that flag. + flags |= ~Pattern.CANON_EQ; + // END android-changed + // No exception expected to match incorrect the reference behaviour + Pattern.compile("foo", flags); + } +} diff --git a/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/PatternSyntaxExceptionTest.java b/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/PatternSyntaxExceptionTest.java new file mode 100644 index 0000000..9f3f389 --- /dev/null +++ b/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/PatternSyntaxExceptionTest.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * 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. + */ + +package org.apache.harmony.regex.tests.java.util.regex; + +import java.util.regex.PatternSyntaxException; + +import junit.framework.TestCase; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargetClass; + +@TestTargetClass(PatternSyntaxException.class) +public class PatternSyntaxExceptionTest extends TestCase { + + @TestTargets({ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "", + method = "PatternSyntaxException", + args = {java.lang.String.class, java.lang.String.class, int.class} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "", + method = "getDescription", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "", + method = "getPattern", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "", + method = "getIndex", + args = {} + ), + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "", + method = "getMessage", + args = {} + ) + }) + public void testPatternSyntaxException() { + // Normal case + PatternSyntaxException e = new PatternSyntaxException("Foo", "Bar", 0); + assertEquals("Foo", e.getDescription()); + assertEquals("Bar", e.getPattern()); + assertEquals(0, e.getIndex()); + + String s = e.getMessage(); + assertTrue(s.contains("Foo")); + assertTrue(s.contains("Bar")); + assertTrue(s.contains("0")); + + // No description specified + e = new PatternSyntaxException(null, "Bar", 0); + assertEquals(null, e.getDescription()); + assertEquals("Bar", e.getPattern()); + assertEquals(0, e.getIndex()); + + s = e.getMessage(); + assertFalse(s.contains("Foo")); + assertTrue(s.contains("Bar")); + assertTrue(s.contains("0")); + + // No pattern specified + e = new PatternSyntaxException("Foo", null, 0); + assertEquals("Foo", e.getDescription()); + assertEquals(null, e.getPattern()); + assertEquals(0, e.getIndex()); + + s = e.getMessage(); + assertTrue(s.contains("Foo")); + assertFalse(s.contains("Bar")); + assertTrue(s.contains("0")); + + // Neither description nor pattern specified + e = new PatternSyntaxException(null, null, 0); + assertEquals(null, e.getDescription()); + assertEquals(null, e.getPattern()); + assertEquals(0, e.getIndex()); + + s = e.getMessage(); + assertFalse(s.contains("Foo")); + assertFalse(s.contains("Bar")); + assertTrue(s.contains("0")); + + // No index specified + e = new PatternSyntaxException("Foo", "Bar", -1); + assertEquals(-1, e.getIndex()); + + s = e.getMessage(); + assertFalse(s.contains("^")); + + // No pattern, but index specified + e = new PatternSyntaxException("Foo", null, 0); + assertEquals(0, e.getIndex()); + + s = e.getMessage(); + assertFalse(s.contains("^")); + } + +} diff --git a/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/PatternTest.java b/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/PatternTest.java new file mode 100644 index 0000000..f70f9f1 --- /dev/null +++ b/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/PatternTest.java @@ -0,0 +1,2410 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.harmony.regex.tests.java.util.regex; + +import dalvik.annotation.BrokenTest; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestLevel; + +import java.io.Serializable; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import junit.framework.TestCase; + +import org.apache.harmony.testframework.serialization.SerializationTest; +import org.apache.harmony.testframework.serialization.SerializationTest.SerializableAssert; + +@TestTargetClass( + value = Pattern.class, + untestedMethods= { + @TestTargetNew( + level = TestLevel.NOT_FEASIBLE, + notes = "finalize is hard to test since the implementation only calls a native function", + method = "finalize", + args = {} + ) + } +) +public class PatternTest extends TestCase { + String[] testPatterns = { + "(a|b)*abb", + "(1*2*3*4*)*567", + "(a|b|c|d)*aab", + "(1|2|3|4|5|6|7|8|9|0)(1|2|3|4|5|6|7|8|9|0)*", + "(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ)*", + "(a|b)*(a|b)*A(a|b)*lice.*", + "(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)(a|b|c|d|e|f|g|h|" + + "i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)*(1|2|3|4|5|6|7|8|9|0)*|while|for|struct|if|do", +// BEGIN android-changed +// We don't have canonical equivalence. +// "x(?c)y", "x(?cc)y" +// "x(?:c)y" +// END android-changed + + }; + + String[] testPatternsAlt = { + /* + * According to JavaDoc 2 and 3 oct digit sequences like \\o70\\o347 + * should be OK, but test is failed for them + */ + "[ab]\\b\\\\o5\\xF9\\u1E7B\\t\\n\\f\\r\\a\\e[yz]", + "^\\p{Lower}*\\p{Upper}*\\p{ASCII}?\\p{Alpha}?\\p{Digit}*\\p{Alnum}\\p{Punct}\\p{Graph}\\p{Print}\\p{Blank}\\p{Cntrl}\\p{XDigit}\\p{Space}", + "$\\p{javaLowerCase}\\p{javaUpperCase}\\p{javaWhitespace}\\p{javaMirrored}", + "\\p{InGreek}\\p{Lu}\\p{Sc}\\P{InGreek}[\\p{L}&&[^\\p{Lu}]]" }; + + String[] wrongTestPatterns = { "\\o9A", "\\p{Lawer}", "\\xG0" }; + + final static int[] flagsSet = { Pattern.CASE_INSENSITIVE, + Pattern.MULTILINE, Pattern.DOTALL, Pattern.UNICODE_CASE + /* , Pattern.CANON_EQ */ }; + + /* + * Based on RI implenetation documents. Need to check this set regarding + * actual implementation. + */ + final static int[] wrongFlagsSet = { 256, 512, 1024 }; + + final static int DEFAULT_FLAGS = 0; + + @TestTargetNew( + level = TestLevel.ADDITIONAL, + notes = "TODO empty test", + method = "!", + args = {} + ) + @BrokenTest("empty test") + public void testMatcher() { + } + + /* + * Class under test for String[] split(CharSequence, int) + */ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of splitsplit(java.lang.String, int) method.", + method = "split", + args = {CharSequence.class, int.class} + ) + public void testSplitCharSequenceint() { + // splitting CharSequence which ends with pattern + // bug6193 + assertEquals(",,".split(",", 3).length, 3); + assertEquals(",,".split(",", 4).length, 3); + // bug6193 + // bug5391 + assertEquals(Pattern.compile("o").split("boo:and:foo", 5).length, 5); + assertEquals(Pattern.compile("b").split("ab", -1).length, 2); + // bug5391 + String s[]; + Pattern pat = Pattern.compile("x"); + s = pat.split("zxx:zzz:zxx", 10); + assertEquals(s.length, 5); + s = pat.split("zxx:zzz:zxx", 3); + assertEquals(s.length, 3); + s = pat.split("zxx:zzz:zxx", -1); + assertEquals(s.length, 5); + s = pat.split("zxx:zzz:zxx", 0); + assertEquals(s.length, 3); + // other splitting + // negative limit + pat = Pattern.compile("b"); + s = pat.split("abccbadfebb", -1); + assertEquals(s.length, 5); + s = pat.split("", -1); + assertEquals(s.length, 1); + pat = Pattern.compile(""); + s = pat.split("", -1); + assertEquals(s.length, 1); + s = pat.split("abccbadfe", -1); + assertEquals(s.length, 11); + // zero limit + pat = Pattern.compile("b"); + s = pat.split("abccbadfebb", 0); + assertEquals(s.length, 3); + s = pat.split("", 0); + assertEquals(s.length, 1); + pat = Pattern.compile(""); + s = pat.split("", 0); + assertEquals(s.length, 1); + s = pat.split("abccbadfe", 0); + assertEquals(s.length, 10); + // positive limit + pat = Pattern.compile("b"); + s = pat.split("abccbadfebb", 12); + assertEquals(s.length, 5); + s = pat.split("", 6); + assertEquals(s.length, 1); + pat = Pattern.compile(""); + s = pat.split("", 11); + assertEquals(s.length, 1); + s = pat.split("abccbadfe", 15); + assertEquals(s.length, 11); + + pat = Pattern.compile("b"); + s = pat.split("abccbadfebb", 5); + assertEquals(s.length, 5); + s = pat.split("", 1); + assertEquals(s.length, 1); + pat = Pattern.compile(""); + s = pat.split("", 1); + assertEquals(s.length, 1); + s = pat.split("abccbadfe", 11); + assertEquals(s.length, 11); + + pat = Pattern.compile("b"); + s = pat.split("abccbadfebb", 3); + assertEquals(s.length, 3); + pat = Pattern.compile(""); + s = pat.split("abccbadfe", 5); + assertEquals(s.length, 5); + } + + /* + * Class under test for String[] split(CharSequence) + */ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of splitsplit(java.lang.String) method.", + method = "split", + args = {CharSequence.class} + ) + public void testSplitCharSequence() { + String s[]; + Pattern pat = Pattern.compile("b"); + s = pat.split("abccbadfebb"); + assertEquals(s.length, 3); + s = pat.split(""); + assertEquals(s.length, 1); + pat = Pattern.compile(""); + s = pat.split(""); + assertEquals(s.length, 1); + s = pat.split("abccbadfe"); + assertEquals(s.length, 10); + // bug6544 + String s1 = ""; + String[] arr = s1.split(":"); + assertEquals(arr.length, 1); + // bug6544 + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Verifies the functionality of pattern() method.", + method = "pattern", + args = {} + ) + public void testPattern() { + /* Positive assertion test. */ + for (String aPattern : testPatterns) { + Pattern p = Pattern.compile(aPattern); + try { + assertTrue(p.pattern().equals(aPattern)); + } catch (Exception e) { + fail("Unexpected exception: " + e); + } + } + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) method.", + method = "compile", + args = {java.lang.String.class} + ) + public void testCompile() { + /* Positive assertion test. */ + for (String aPattern : testPatterns) { + try { + Pattern p = Pattern.compile(aPattern); + } catch (Exception e) { + fail("Unexpected exception: " + e); + } + } + + /* Positive assertion test with alternative templates. */ + for (String aPattern : testPatternsAlt) { + try { + Pattern p = Pattern.compile(aPattern); + } catch (Exception e) { + fail("Unexpected exception: " + e); + } + } + + /* Negative assertion test. */ + for (String aPattern : wrongTestPatterns) { + try { + Pattern p = Pattern.compile(aPattern); + fail("PatternSyntaxException is expected"); + } catch (PatternSyntaxException pse) { + /* OKAY */ + } catch (Exception e) { + fail("Unexpected exception: " + e); + } + } + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) method for different flags.", + method = "compile", + args = {java.lang.String.class} + ) + public void testFlags() { + String baseString; + String testString; + Pattern pat; + Matcher mat; + + baseString = "((?i)|b)a"; + testString = "A"; + pat = Pattern.compile(baseString); + mat = pat.matcher(testString); + assertFalse(mat.matches()); + + baseString = "(?i)a|b"; + testString = "A"; + pat = Pattern.compile(baseString); + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + baseString = "(?i)a|b"; + testString = "B"; + pat = Pattern.compile(baseString); + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + baseString = "c|(?i)a|b"; + testString = "B"; + pat = Pattern.compile(baseString); + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + baseString = "(?i)a|(?s)b"; + testString = "B"; + pat = Pattern.compile(baseString); + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + baseString = "(?i)a|(?-i)b"; + testString = "B"; + pat = Pattern.compile(baseString); + mat = pat.matcher(testString); + assertFalse(mat.matches()); + + baseString = "(?i)a|(?-i)c|b"; + testString = "B"; + pat = Pattern.compile(baseString); + mat = pat.matcher(testString); + assertFalse(mat.matches()); + + baseString = "(?i)a|(?-i)c|(?i)b"; + testString = "B"; + pat = Pattern.compile(baseString); + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + baseString = "(?i)a|(?-i)b"; + testString = "A"; + pat = Pattern.compile(baseString); + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + baseString = "((?i))a"; + testString = "A"; + pat = Pattern.compile(baseString); + mat = pat.matcher(testString); + assertFalse(mat.matches()); + + baseString = "|(?i)|a"; + testString = "A"; + pat = Pattern.compile(baseString); + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + baseString = "(?i)((?s)a.)"; + testString = "A\n"; + pat = Pattern.compile(baseString); + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + baseString = "(?i)((?-i)a)"; + testString = "A"; + pat = Pattern.compile(baseString); + mat = pat.matcher(testString); + assertFalse(mat.matches()); + + baseString = "(?i)(?s:a.)"; + testString = "A\n"; + pat = Pattern.compile(baseString); + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + baseString = "(?i)fgh(?s:aa)"; + testString = "fghAA"; + pat = Pattern.compile(baseString); + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + baseString = "(?i)((?-i))a"; + testString = "A"; + pat = Pattern.compile(baseString); + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + baseString = "abc(?i)d"; + testString = "ABCD"; + pat = Pattern.compile(baseString); + mat = pat.matcher(testString); + assertFalse(mat.matches()); + + testString = "abcD"; + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + baseString = "a(?i)a(?-i)a(?i)a(?-i)a"; + testString = "aAaAa"; + pat = Pattern.compile(baseString); + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + testString = "aAAAa"; + mat = pat.matcher(testString); + assertFalse(mat.matches()); + } + +// BEGIN android-removed +// The flags() method should only return those flags that were explicitly +// passed during the compilation. The JDK also accepts the ones implicitly +// contained in the pattern, but ICU doesn't do this. +// +// public void testFlagsMethod() { +// String baseString; +// Pattern pat; +// +// /* +// * These tests are for compatibility with RI only. Logically we have to +// * return only flags specified during the compilation. For example +// * pat.flags() == 0 when we compile Pattern pat = +// * Pattern.compile("(?i)abc(?-i)"); but the whole expression is compiled +// * in a case insensitive manner. So there is little sense to do calls to +// * flags() now. +// */ +// baseString = "(?-i)"; +// pat = Pattern.compile(baseString); +// +// baseString = "(?idmsux)abc(?-i)vg(?-dmu)"; +// pat = Pattern.compile(baseString); +// assertEquals(pat.flags(), Pattern.DOTALL | Pattern.COMMENTS); +// +// baseString = "(?idmsux)abc|(?-i)vg|(?-dmu)"; +// pat = Pattern.compile(baseString); +// assertEquals(pat.flags(), Pattern.DOTALL | Pattern.COMMENTS); +// +// baseString = "(?is)a((?x)b.)"; +// pat = Pattern.compile(baseString); +// assertEquals(pat.flags(), Pattern.DOTALL | Pattern.CASE_INSENSITIVE); +// +// baseString = "(?i)a((?-i))"; +// pat = Pattern.compile(baseString); +// assertEquals(pat.flags(), Pattern.CASE_INSENSITIVE); +// +// baseString = "((?i)a)"; +// pat = Pattern.compile(baseString); +// assertEquals(pat.flags(), 0); +// +// pat = Pattern.compile("(?is)abc"); +// assertEquals(pat.flags(), Pattern.CASE_INSENSITIVE | Pattern.DOTALL); +// } +//END android-removed + + /* + * Check default flags when they are not specified in pattern. Based on RI + * since could not find that info + */ + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of flags() method for default flags.", + method = "flags", + args = {} + ) + public void testFlagsCompileDefault() { + for (String pat : testPatternsAlt) { + try { + Pattern p = Pattern.compile(pat); + assertEquals(p.flags(), DEFAULT_FLAGS); + } catch (Exception e) { + fail("Unexpected exception: " + e); + } + } + } + + /* + * Check that flags specified during compile are set properly This is a + * simple implementation that does not use flags combinations. Need to + * improve. + */ + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String, int) & flags() methods. Checks that compilation was corect.", + method = "flags", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String, int) & flags() methods. Checks that compilation was corect.", + method = "compile", + args = {java.lang.String.class, int.class} + ) + }) + public void testFlagsCompileValid() { + for (String pat : testPatternsAlt) { + for (int flags : flagsSet) { + try { + Pattern p = Pattern.compile(pat, flags); + assertEquals(p.flags(), flags); + } catch (Exception e) { + fail("Unexpected exception: " + e); + } + } + } + } + + /* + * Class under test for Pattern compile(String, int) + */ + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) method.Checks that correct exceptions were thrown.", + method = "compile", + args = {java.lang.String.class} + ) + public void testCompileStringint() { + /* + * these tests are needed to verify that appropriate exceptions are + * thrown + */ + String pattern = "b)a"; + try { + Pattern.compile(pattern); + fail("Expected a PatternSyntaxException when compiling pattern: " + + pattern); + } catch (PatternSyntaxException e) { + // pass + } + pattern = "bcde)a"; + try { + Pattern.compile(pattern); + fail("Expected a PatternSyntaxException when compiling pattern: " + + pattern); + } catch (PatternSyntaxException e) { + // pass + } + pattern = "bbg())a"; + try { + Pattern pat = Pattern.compile(pattern); + fail("Expected a PatternSyntaxException when compiling pattern: " + + pattern); + } catch (PatternSyntaxException e) { + // pass + } + + pattern = "cdb(?i))a"; + try { + Pattern pat = Pattern.compile(pattern); + fail("Expected a PatternSyntaxException when compiling pattern: " + + pattern); + } catch (PatternSyntaxException e) { + // pass + } + + /* + * This pattern should compile - HARMONY-2127 + */ +// pattern = "x(?c)y"; +// Pattern.compile(pattern); + + /* + * this pattern doesn't match any string, but should be compiled anyway + */ + pattern = "(b\\1)a"; + Pattern.compile(pattern); + } + + /* + * Class under test for Pattern compile(String) + */ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) method.Checks that correct exceptions were thrown.", + method = "compile", + args = {java.lang.String.class} + ) + public void testQuantCompileNeg() { + String[] patterns = { "5{,2}", "{5asd", "{hgdhg", "{5,hjkh", "{,5hdsh", + "{5,3shdfkjh}" }; + for (String element : patterns) { + try { + Pattern.compile(element); + fail("PatternSyntaxException was expected, but compilation succeeds"); + } catch (PatternSyntaxException pse) { + continue; + } + } + // Regression for HARMONY-1365 +// BEGIN android-changed +// Original regex contained some illegal stuff. Changed it slightly, +// while maintaining the wicked character of this "mother of all +// regexes". +// String pattern = "(?![^\\<C\\f\\0146\\0270\\}&&[|\\02-\\x3E\\}|X-\\|]]{7,}+)[|\\\\\\x98\\<\\?\\u4FCFr\\,\\0025\\}\\004|\\0025-\\052\061]|(?<![|\\01-\\u829E])|(?<!\\p{Alpha})|^|(?-s:[^\\x15\\\\\\x24F\\a\\,\\a\\u97D8[\\x38\\a[\\0224-\\0306[^\\0020-\\u6A57]]]]??)(?uxix:[^|\\{\\[\\0367\\t\\e\\x8C\\{\\[\\074c\\]V[|b\\fu\\r\\0175\\<\\07f\\066s[^D-\\x5D]]])(?xx:^{5,}+)(?uuu)(?=^\\D)|(?!\\G)(?>\\G*?)(?![^|\\]\\070\\ne\\{\\t\\[\\053\\?\\\\\\x51\\a\\075\\0023-\\[&&[|\\022-\\xEA\\00-\\u41C2&&[^|a-\\xCC&&[^\\037\\uECB3\\u3D9A\\x31\\|\\<b\\0206\\uF2EC\\01m\\,\\ak\\a\\03&&\\p{Punct}]]]])(?-dxs:[|\\06-\\07|\\e-\\x63&&[|Tp\\u18A3\\00\\|\\xE4\\05\\061\\015\\0116C|\\r\\{\\}\\006\\xEA\\0367\\xC4\\01\\0042\\0267\\xBB\\01T\\}\\0100\\?[|\\[-\\u459B|\\x23\\x91\\rF\\0376[|\\?-\\x94\\0113-\\\\\\s]]]]{6}?)(?<=[^\\t-\\x42H\\04\\f\\03\\0172\\?i\\u97B6\\e\\f\\uDAC2])(?=\\B*+)(?>[^\\016\\r\\{\\,\\uA29D\\034\\02[\\02-\\[|\\t\\056\\uF599\\x62\\e\\<\\032\\uF0AC\\0026\\0205Q\\|\\\\\\06\\0164[|\\057-\\u7A98&&[\\061-g|\\|\\0276\\n\\042\\011\\e\\xE8\\x64B\\04\\u6D0EDW^\\p{Lower}]]]]?)(?<=[^\\n\\\\\\t\\u8E13\\,\\0114\\u656E\\xA5\\]&&[\\03-\\026|\\uF39D\\01\\{i\\u3BC2\\u14FE]])(?<=[^|\\uAE62\\054H\\|\\}&&^\\p{Space}])(?sxx)(?<=[\\f\\006\\a\\r\\xB4]*+)|(?x-xd:^{5}+)()"; + String pattern = "(?![^\\<C\\f\\0146\\0270\\}&&[|\\02-\\x3E\\}|X-\\|]]{7,}+)[|\\\\\\x98\\<\\?\\u4FCFr\\,\\0025\\}\\004|\\0025-\\052\061]|(?<![|\\01-\\u829E])|(?<!\\p{Alpha})|^|(?-s:[^\\x15\\\\\\x24F\\a\\,\\a\\u97D8[\\x38\\a[\\0224-\\0306[^\\0020-\\u6A57]]]]??)(?uxix:[^|\\{\\[\\0367\\t\\e\\x8C\\{\\[\\074c\\]V[|b\\fu\\r\\0175\\<\\07f\\066s[^D-\\x5D]]])(?xx:^{5,}+)(?uuu)(?=^\\D)|(?!\\G)(?>\\.*?)(?![^|\\]\\070\\ne\\{\\t\\[\\053\\?\\\\\\x51\\a\\075\\0023-\\[&&[|\\022-\\xEA\\00-\\u41C2&&[^|a-\\xCC&&[^\\037\\uECB3\\u3D9A\\x31\\|\\<b\\0206\\uF2EC\\01m\\,\\ak\\a\\03&&\\p{Punct}]]]])(?-dxs:[|\\06-\\07|\\e-\\x63&&[|Tp\\u18A3\\00\\|\\xE4\\05\\061\\015\\0116C|\\r\\{\\}\\006\\xEA\\0367\\xC4\\01\\0042\\0267\\xBB\\01T\\}\\0100\\?[|\\[-\\u459B|\\x23\\x91\\rF\\0376[|\\?-\\x94\\0113-\\\\\\s]]]]{6}?)(?<=[^\\t-\\x42H\\04\\f\\03\\0172\\?i\\u97B6\\e\\f\\uDAC2])(?=\\.*+)(?>[^\\016\\r\\{\\,\\uA29D\\034\\02[\\02-\\[|\\t\\056\\uF599\\x62\\e\\<\\032\\uF0AC\\0026\\0205Q\\|\\\\\\06\\0164[|\\057-\\u7A98&&[\\061-g|\\|\\0276\\n\\042\\011\\e\\xE8\\x64B\\04\\u6D0EDW^\\p{Lower}]]]]?)(?<=[^\\n\\\\\\t\\u8E13\\,\\0114\\u656E\\xA5\\]&&[\\03-\\026|\\uF39D\\01\\{i\\u3BC2\\u14FE]])(?<=[^|\\uAE62\\054H\\|\\}&&^\\p{Space}])(?sxx)(?<=[\\f\\006\\a\\r\\xB4]{1,5})|(?x-xd:^{5}+)()"; +// END android-changed + assertNotNull(Pattern.compile(pattern)); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) method.", + method = "compile", + args = {java.lang.String.class} + ) + public void testQuantCompilePos() { + String[] patterns = {/* "(abc){1,3}", */"abc{2,}", "abc{5}" }; + for (String element : patterns) { + Pattern.compile(element); + } + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile() method. Also tested methods from matcher: matches(), start(int), group(int)", + method = "compile", + args = {java.lang.String.class} + ) + public void testQuantComposition() { + String pattern = "(a{1,3})aab"; + java.util.regex.Pattern pat = java.util.regex.Pattern.compile(pattern); + java.util.regex.Matcher mat = pat.matcher("aaab"); + mat.matches(); + mat.start(1); + mat.group(1); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "", + method = "matches", + args = {java.lang.String.class, java.lang.CharSequence.class} + ) + public void testMatches() { + String[][] posSeq = { + { "abb", "ababb", "abababbababb", "abababbababbabababbbbbabb" }, + { "213567", "12324567", "1234567", "213213567", + "21312312312567", "444444567" }, + { "abcdaab", "aab", "abaab", "cdaab", "acbdadcbaab" }, + { "213234567", "3458", "0987654", "7689546432", "0398576", + "98432", "5" }, + { + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" }, + { "ababbaAabababblice", "ababbaAliceababab", "ababbAabliceaaa", + "abbbAbbbliceaaa", "Alice" }, + { "a123", "bnxnvgds156", "for", "while", "if", "struct" }, + { "xy" }, { "xy" }, { "xcy" } + + }; + + for (int i = 0; i < testPatterns.length; i++) { + for (int j = 0; j < posSeq[i].length; j++) { + assertTrue("Incorrect match: " + testPatterns[i] + " vs " + + posSeq[i][j], Pattern.matches(testPatterns[i], + posSeq[i][j])); + } + } + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies exception", + method = "matches", + args = {java.lang.String.class, java.lang.CharSequence.class} + ) + public void testMatchesException() { + /* Negative assertion test. */ + for (String aPattern : wrongTestPatterns) { + try { + Pattern.matches(aPattern, "Foo"); + fail("PatternSyntaxException is expected"); + } catch (PatternSyntaxException pse) { + /* OKAY */ + } catch (Exception e) { + fail("Unexpected exception: " + e); + } + } + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "The test verifies the functionality of matches(java.lang.String,java.lang.CharSequence) method.", + method = "matches", + args = {java.lang.String.class, java.lang.CharSequence.class} + ) + public void testTimeZoneIssue() { + Pattern p = Pattern.compile("GMT(\\+|\\-)(\\d+)(:(\\d+))?"); + Matcher m = p.matcher("GMT-9:45"); + assertTrue(m.matches()); + assertEquals("-", m.group(1)); + assertEquals("9", m.group(2)); + assertEquals(":45", m.group(3)); + assertEquals("45", m.group(4)); + } + +// BEGIN android-changed +// Removed one pattern that is buggy on the JDK. We don't want to duplicate that. + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of matches(java.lang.String,java.lang.CharSequence) method.", + method = "matches", + args = {java.lang.String.class, java.lang.CharSequence.class} + ) + public void testCompileRanges() { + String[] correctTestPatterns = { "[^]*abb]*", /* "[^a-d[^m-p]]*abb", */ + "[a-d\\d]*abb", "[abc]*abb", "[a-e&&[de]]*abb", "[^abc]*abb", + "[a-e&&[^de]]*abb", "[a-z&&[^m-p]]*abb", "[a-d[m-p]]*abb", + "[a-zA-Z]*abb", "[+*?]*abb", "[^+*?]*abb" }; + + String[] inputSecuence = { "kkkk", /* "admpabb", */ "abcabcd124654abb", + "abcabccbacababb", "dededededededeedabb", "gfdhfghgdfghabb", + "accabacbcbaabb", "acbvfgtyabb", "adbcacdbmopabcoabb", + "jhfkjhaSDFGHJkdfhHNJMjkhfabb", "+*??+*abb", "sdfghjkabb" }; + + Pattern pat; + + for (int i = 0; i < correctTestPatterns.length; i++) { + assertTrue("pattern: " + correctTestPatterns[i] + " input: " + + inputSecuence[i], Pattern.matches(correctTestPatterns[i], + inputSecuence[i])); + + } + + String[] wrongInputSecuence = { "]", /* "admpkk", */ "abcabcd124k654abb", + "abwcabccbacababb", "abababdeababdeabb", "abcabcacbacbabb", + "acdcbecbaabb", "acbotyabb", "adbcaecdbmopabcoabb", + "jhfkjhaSDFGHJk;dfhHNJMjkhfabb", "+*?a?+*abb", "sdf+ghjkabb" }; + + for (int i = 0; i < correctTestPatterns.length; i++) { + assertFalse("pattern: " + correctTestPatterns[i] + " input: " + + wrongInputSecuence[i], Pattern.matches( + correctTestPatterns[i], wrongInputSecuence[i])); + + } + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of matches(java.lang.String,java.lang.CharSequence) method for ranged patterns.", + method = "matches", + args = {java.lang.String.class, java.lang.CharSequence.class} + ) + public void testRangesSpecialCases() { + String neg_patterns[] = { "[a-&&[b-c]]", "[a-\\w]", "[b-a]", "[]" }; + + for (String element : neg_patterns) { + try { + Pattern.compile(element); + fail("PatternSyntaxException was expected: " + element); + } catch (PatternSyntaxException pse) { + } + } + + String pos_patterns[] = { "[-]+", "----", "[a-]+", "a-a-a-a-aa--", + "[\\w-a]+", "123-2312--aaa-213", "[a-]]+", "-]]]]]]]]]]]]]]]" }; + + for (int i = 0; i < pos_patterns.length; i++) { + String pat = pos_patterns[i++]; + String inp = pos_patterns[i]; + assertTrue("pattern: " + pat + " input: " + inp, Pattern.matches( + pat, inp)); + } + } + // END android-changed + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "The test verifies the functionality of matches(java.lang.String,java.lang.CharSequence) method.", + method = "matches", + args = {java.lang.String.class, java.lang.CharSequence.class} + ) +public void testZeroSymbols() { + assertTrue(Pattern.matches("[\0]*abb", "\0\0\0\0\0\0abb")); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of matcher(java.lang.String) method.", + method = "matcher", + args = {CharSequence.class} + ) + public void testEscapes() { + Pattern pat = Pattern.compile("\\Q{]()*?"); + Matcher mat = pat.matcher("{]()*?"); + + assertTrue(mat.matches()); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) method.", + method = "compile", + args = {java.lang.String.class} + ) + public void testBug181() { + Pattern.compile("[\\t-\\r]"); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) method.", + method = "compile", + args = {java.lang.String.class} + ) + public void testOrphanQuantifiers() { + try { + Pattern.compile("+++++"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException pse) { + } + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) method.", + method = "compile", + args = {java.lang.String.class} + ) + public void testOrphanQuantifiers2() { + try { + Pattern pat = Pattern.compile("\\d+*"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException pse) { + } + } + + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) method.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) method.", + method = "compile", + args = {java.lang.String.class} + ) + }) + public void testBug197() { + Object[] vals = { ":", new Integer(2), + new String[] { "boo", "and:foo" }, ":", new Integer(5), + new String[] { "boo", "and", "foo" }, ":", new Integer(-2), + new String[] { "boo", "and", "foo" }, ":", new Integer(3), + new String[] { "boo", "and", "foo" }, ":", new Integer(1), + new String[] { "boo:and:foo" }, "o", new Integer(5), + new String[] { "b", "", ":and:f", "", "" }, "o", + new Integer(4), new String[] { "b", "", ":and:f", "o" }, "o", + new Integer(-2), new String[] { "b", "", ":and:f", "", "" }, + "o", new Integer(0), new String[] { "b", "", ":and:f" } }; + + for (int i = 0; i < vals.length / 3;) { + String[] res = Pattern.compile(vals[i++].toString()).split( + "boo:and:foo", ((Integer) vals[i++]).intValue()); + String[] expectedRes = (String[]) vals[i++]; + + assertEquals(expectedRes.length, res.length); + + for (int j = 0; j < expectedRes.length; j++) { + assertEquals(expectedRes[j], res[j]); + } + } + } + + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "The test verifies the functionality of compile(java.lang.String) method.", + method = "compile", + args = {java.lang.String.class} + ) + public void testURIPatterns() { + String URI_REGEXP_STR = "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"; + String SCHEME_REGEXP_STR = "^[a-zA-Z]{1}[\\w+-.]+$"; + String REL_URI_REGEXP_STR = "^(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"; + String IPV6_REGEXP_STR = "^[0-9a-fA-F\\:\\.]+(\\%\\w+)?$"; + String IPV6_REGEXP_STR2 = "^\\[[0-9a-fA-F\\:\\.]+(\\%\\w+)?\\]$"; + String IPV4_REGEXP_STR = "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$"; + String HOSTNAME_REGEXP_STR = "\\w+[\\w\\-\\.]*"; + + Pattern URI_REGEXP = Pattern.compile(URI_REGEXP_STR); + Pattern REL_URI_REGEXP = Pattern.compile(REL_URI_REGEXP_STR); + Pattern SCHEME_REGEXP = Pattern.compile(SCHEME_REGEXP_STR); + Pattern IPV4_REGEXP = Pattern.compile(IPV4_REGEXP_STR); + Pattern IPV6_REGEXP = Pattern.compile(IPV6_REGEXP_STR); + Pattern IPV6_REGEXP2 = Pattern.compile(IPV6_REGEXP_STR2); + Pattern HOSTNAME_REGEXP = Pattern.compile(HOSTNAME_REGEXP_STR); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) method.", + method = "compile", + args = {java.lang.String.class} + ) + public void testFindBoundaryCases1() { + Pattern pat = Pattern.compile(".*\n"); + Matcher mat = pat.matcher("a\n"); + + mat.find(); + assertEquals("a\n", mat.group()); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) method.", + method = "compile", + args = {java.lang.String.class} + ) + public void testFindBoundaryCases2() { + Pattern pat = Pattern.compile(".*A"); + Matcher mat = pat.matcher("aAa"); + + mat.find(); + assertEquals("aA", mat.group()); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) method.", + method = "compile", + args = {java.lang.String.class} + ) + public void testFindBoundaryCases3() { + Pattern pat = Pattern.compile(".*A"); + Matcher mat = pat.matcher("a\naA\n"); + + mat.find(); + assertEquals("aA", mat.group()); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) method.", + method = "compile", + args = {java.lang.String.class} + ) + public void testFindBoundaryCases4() { + Pattern pat = Pattern.compile("A.*"); + Matcher mat = pat.matcher("A\n"); + + mat.find(); + assertEquals("A", mat.group()); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) method.", + method = "compile", + args = {java.lang.String.class} + ) + public void testFindBoundaryCases5() { + Pattern pat = Pattern.compile(".*A.*"); + Matcher mat = pat.matcher("\nA\naaa\nA\naaAaa\naaaA\n"); + // Matcher mat = pat.matcher("\nA\n"); + String[] res = { "A", "A", "aaAaa", "aaaA" }; + int k = 0; + for (; mat.find(); k++) { + assertEquals(res[k], mat.group()); + } + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) method.", + method = "compile", + args = {java.lang.String.class} + ) + public void testFindBoundaryCases6() { + String[] res = { "", "a", "", "" }; + Pattern pat = Pattern.compile(".*"); + Matcher mat = pat.matcher("\na\n"); + int k = 0; + + for (; mat.find(); k++) { + assertEquals(res[k], mat.group()); + } + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testBackReferences() { + Pattern pat = Pattern.compile("(\\((\\w*):(.*):(\\2)\\))"); + Matcher mat = pat + .matcher("(start1: word :start1)(start2: word :start2)"); + int k = 1; + for (; mat.find(); k++) { + assertEquals("start" + k, mat.group(2)); + assertEquals(" word ", mat.group(3)); + assertEquals("start" + k, mat.group(4)); + } + + assertEquals(3, k); + pat = Pattern.compile(".*(.)\\1"); + mat = pat.matcher("saa"); + assertTrue(mat.matches()); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String, int) & matcher(java.lang.CharSequence) methods.", + method = "compile", + args = {java.lang.String.class, int.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String, int) & matcher(java.lang.CharSequence) methods.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testNewLine() { + Pattern pat = Pattern.compile("(^$)*\n", Pattern.MULTILINE); + Matcher mat = pat.matcher("\r\n\n"); + int counter = 0; + while (mat.find()) { + counter++; + } + assertEquals(2, counter); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String, int) & matcher(java.lang.CharSequence) methods.", + method = "compile", + args = {java.lang.String.class, int.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String, int) & matcher(java.lang.CharSequence) methods.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testFindGreedy() { + Pattern pat = Pattern.compile(".*aaa", Pattern.DOTALL); + Matcher mat = pat.matcher("aaaa\naaa\naaaaaa"); + mat.matches(); + assertEquals(15, mat.end()); + } + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies serialization/deserialization.", + method = "!SerializationSelf", + args = {} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies serialization/deserialization.", + method = "!SerializationGolden", + args = {} + ) + }) + public void testSerialization() throws Exception { + Pattern pat = Pattern.compile("a*bc"); + SerializableAssert comparator = new SerializableAssert() { + public void assertDeserialized(Serializable initial, + Serializable deserialized) { + assertEquals(((Pattern) initial).toString(), + ((Pattern) deserialized).toString()); + } + }; + SerializationTest.verifyGolden(this, pat, comparator); + SerializationTest.verifySelf(pat, comparator); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String, int) & matcher(java.lang.CharSequence) methods.", + method = "compile", + args = {java.lang.String.class, int.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String, int) & matcher(java.lang.CharSequence) methods.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testSOLQuant() { + Pattern pat = Pattern.compile("$*", Pattern.MULTILINE); + Matcher mat = pat.matcher("\n\n"); + int counter = 0; + while (mat.find()) { + counter++; + } + + assertEquals(3, counter); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) method.", + method = "compile", + args = {java.lang.String.class} + ) + public void testIllegalEscape() { + try { + Pattern.compile("\\y"); + fail("PatternSyntaxException expected"); + } catch (PatternSyntaxException pse) { + } + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) method.", + method = "compile", + args = {java.lang.String.class} + ) + public void testEmptyFamily() { + Pattern.compile("\\p{Lower}"); + String a = "*"; + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testNonCaptConstr() { + // Flags + Pattern pat = Pattern.compile("(?i)b*(?-i)a*"); + assertTrue(pat.matcher("bBbBaaaa").matches()); + assertFalse(pat.matcher("bBbBAaAa").matches()); + + // Non-capturing groups + pat = Pattern.compile("(?i:b*)a*"); + assertTrue(pat.matcher("bBbBaaaa").matches()); + assertFalse(pat.matcher("bBbBAaAa").matches()); + + pat = Pattern + // 1 2 3 4 5 6 7 8 9 10 11 + .compile("(?:-|(-?\\d+\\d\\d\\d))?(?:-|-(\\d\\d))?(?:-|-(\\d\\d))?(T)?(?:(\\d\\d):(\\d\\d):(\\d\\d)(\\.\\d+)?)?(?:(?:((?:\\+|\\-)\\d\\d):(\\d\\d))|(Z))?"); + Matcher mat = pat.matcher("-1234-21-31T41:51:61.789+71:81"); + assertTrue(mat.matches()); + assertEquals("-1234", mat.group(1)); + assertEquals("21", mat.group(2)); + assertEquals("31", mat.group(3)); + assertEquals("T", mat.group(4)); + assertEquals("41", mat.group(5)); + assertEquals("51", mat.group(6)); + assertEquals("61", mat.group(7)); + assertEquals(".789", mat.group(8)); + assertEquals("+71", mat.group(9)); + assertEquals("81", mat.group(10)); + + // positive lookahead + pat = Pattern.compile(".*\\.(?=log$).*$"); + assertTrue(pat.matcher("a.b.c.log").matches()); + assertFalse(pat.matcher("a.b.c.log.").matches()); + + // negative lookahead + pat = Pattern.compile(".*\\.(?!log$).*$"); + assertFalse(pat.matcher("abc.log").matches()); + assertTrue(pat.matcher("abc.logg").matches()); + + // positive lookbehind + pat = Pattern.compile(".*(?<=abc)\\.log$"); + assertFalse(pat.matcher("cde.log").matches()); + assertTrue(pat.matcher("abc.log").matches()); + + // negative lookbehind + pat = Pattern.compile(".*(?<!abc)\\.log$"); + assertTrue(pat.matcher("cde.log").matches()); + assertFalse(pat.matcher("abc.log").matches()); + + // atomic group + pat = Pattern.compile("(?>a*)abb"); + assertFalse(pat.matcher("aaabb").matches()); + pat = Pattern.compile("(?>a*)bb"); + assertTrue(pat.matcher("aaabb").matches()); + + pat = Pattern.compile("(?>a|aa)aabb"); + assertTrue(pat.matcher("aaabb").matches()); + pat = Pattern.compile("(?>aa|a)aabb"); + assertFalse(pat.matcher("aaabb").matches()); + +// BEGIN android-removed +// Questionable constructs that ICU doesn't support. +// // quantifiers over look ahead +// pat = Pattern.compile(".*(?<=abc)*\\.log$"); +// assertTrue(pat.matcher("cde.log").matches()); +// pat = Pattern.compile(".*(?<=abc)+\\.log$"); +// assertFalse(pat.matcher("cde.log").matches()); +// END android-removed + + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) method.", + method = "compile", + args = {java.lang.String.class} + ) + public void testCorrectReplacementBackreferencedJointSet() { + Pattern pat = Pattern.compile("ab(a)*\\1"); + pat = Pattern.compile("abc(cd)fg"); + pat = Pattern.compile("aba*cd"); + pat = Pattern.compile("ab(a)*+cd"); + pat = Pattern.compile("ab(a)*?cd"); + pat = Pattern.compile("ab(a)+cd"); + pat = Pattern.compile(".*(.)\\1"); + pat = Pattern.compile("ab((a)|c|d)e"); + pat = Pattern.compile("abc((a(b))cd)"); + pat = Pattern.compile("ab(a)++cd"); + pat = Pattern.compile("ab(a)?(c)d"); + pat = Pattern.compile("ab(a)?+cd"); + pat = Pattern.compile("ab(a)??cd"); + pat = Pattern.compile("ab(a)??cd"); + pat = Pattern.compile("ab(a){1,3}?(c)d"); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testCompilePatternWithTerminatorMark() { + Pattern pat = Pattern.compile("a\u0000\u0000cd"); + Matcher mat = pat.matcher("a\u0000\u0000cd"); + assertTrue(mat.matches()); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testAlternations() { + String baseString = "|a|bc"; + Pattern pat = Pattern.compile(baseString); + Matcher mat = pat.matcher(""); + + assertTrue(mat.matches()); + + baseString = "a||bc"; + pat = Pattern.compile(baseString); + mat = pat.matcher(""); + assertTrue(mat.matches()); + + baseString = "a|bc|"; + pat = Pattern.compile(baseString); + mat = pat.matcher(""); + assertTrue(mat.matches()); + + baseString = "a|b|"; + pat = Pattern.compile(baseString); + mat = pat.matcher(""); + assertTrue(mat.matches()); + + baseString = "a(|b|cd)e"; + pat = Pattern.compile(baseString); + mat = pat.matcher("ae"); + assertTrue(mat.matches()); + + baseString = "a(b||cd)e"; + pat = Pattern.compile(baseString); + mat = pat.matcher("ae"); + assertTrue(mat.matches()); + + baseString = "a(b|cd|)e"; + pat = Pattern.compile(baseString); + mat = pat.matcher("ae"); + assertTrue(mat.matches()); + + baseString = "a(b|c|)e"; + pat = Pattern.compile(baseString); + mat = pat.matcher("ae"); + assertTrue(mat.matches()); + + baseString = "a(|)e"; + pat = Pattern.compile(baseString); + mat = pat.matcher("ae"); + assertTrue(mat.matches()); + + baseString = "|"; + pat = Pattern.compile(baseString); + mat = pat.matcher(""); + assertTrue(mat.matches()); + + baseString = "a(?:|)e"; + pat = Pattern.compile(baseString); + mat = pat.matcher("ae"); + assertTrue(mat.matches()); + + baseString = "a||||bc"; + pat = Pattern.compile(baseString); + mat = pat.matcher(""); + assertTrue(mat.matches()); + + baseString = "(?i-is)|a"; + pat = Pattern.compile(baseString); + mat = pat.matcher("a"); + assertTrue(mat.matches()); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testMatchWithGroups() { + String baseString = "jwkerhjwehrkwjehrkwjhrwkjehrjwkehrjkwhrkwehrkwhrkwrhwkhrwkjehr"; + String pattern = ".*(..).*\\1.*"; + assertTrue(Pattern.compile(pattern).matcher(baseString).matches()); + + baseString = "saa"; + pattern = ".*(.)\\1"; + assertTrue(Pattern.compile(pattern).matcher(baseString).matches()); + assertTrue(Pattern.compile(pattern).matcher(baseString).find()); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies split method for empty string.", + method = "split", + args = {java.lang.CharSequence.class} + ) + public void testSplitEmptyCharSequence() { + String s1 = ""; + String[] arr = s1.split(":"); + assertEquals(arr.length, 1); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "The test verifies the functionality of compile(java.lang.String) & split(java.lang.CharSequence, int) methods.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "The test verifies the functionality of compile(java.lang.String) & split(java.lang.CharSequence, int) methods.", + method = "split", + args = {java.lang.CharSequence.class, int.class} + ) + }) + public void testSplitEndsWithPattern() { + assertEquals(",,".split(",", 3).length, 3); + assertEquals(",,".split(",", 4).length, 3); + + assertEquals(Pattern.compile("o").split("boo:and:foo", 5).length, 5); + assertEquals(Pattern.compile("b").split("ab", -1).length, 2); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "The test verifies the functionality of matches(java.lang.String), java.lang.CharSequence) method for case insensitive flags.", + method = "matches", + args = {java.lang.String.class, java.lang.CharSequence.class} + ) + public void testCaseInsensitiveFlag() { + assertTrue(Pattern.matches("(?i-:AbC)", "ABC")); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testEmptyGroups() { + Pattern pat = Pattern.compile("ab(?>)cda"); + Matcher mat = pat.matcher("abcda"); + assertTrue(mat.matches()); + + pat = Pattern.compile("ab()"); + mat = pat.matcher("ab"); + assertTrue(mat.matches()); + + pat = Pattern.compile("abc(?:)(..)"); + mat = pat.matcher("abcgf"); + assertTrue(mat.matches()); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & compile(java.lang.String, int) methods.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & compile(java.lang.String, int) methods.", + method = "compile", + args = {java.lang.String.class, int.class} + ) + }) + public void testCompileNonCaptGroup() { + boolean isCompiled = false; + + try { +// BEGIN android-change +// We don't have canonical equivalence. + Pattern pat = Pattern.compile("(?:)"); + pat = Pattern.compile("(?:)", Pattern.DOTALL); + pat = Pattern.compile("(?:)", Pattern.CASE_INSENSITIVE); + pat = Pattern.compile("(?:)", Pattern.COMMENTS | Pattern.UNIX_LINES); +// END android-change + isCompiled = true; + } catch (PatternSyntaxException e) { + System.out.println(e); + } + assertTrue(isCompiled); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testEmbeddedFlags() { + String baseString = "(?i)((?s)a)"; + String testString = "A"; + Pattern pat = Pattern.compile(baseString); + Matcher mat = pat.matcher(testString); + assertTrue(mat.matches()); + + baseString = "(?x)(?i)(?s)(?d)a"; + testString = "A"; + pat = Pattern.compile(baseString); + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + baseString = "(?x)(?i)(?s)(?d)a."; + testString = "a\n"; + pat = Pattern.compile(baseString); + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + baseString = "abc(?x:(?i)(?s)(?d)a.)"; + testString = "abcA\n"; + pat = Pattern.compile(baseString); + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + baseString = "abc((?x)d)(?i)(?s)a"; + testString = "abcdA"; + pat = Pattern.compile(baseString); + mat = pat.matcher(testString); + assertTrue(mat.matches()); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) method.", + method = "compile", + args = {java.lang.String.class} + ) + public void testAltWithFlags() { + boolean isCompiled = false; + + try { + Pattern pat = Pattern.compile("|(?i-xi)|()"); + isCompiled = true; + } catch (PatternSyntaxException e) { + System.out.println(e); + } + assertTrue(isCompiled); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) +public void testRestoreFlagsAfterGroup() { + String baseString = "abc((?x)d) a"; + String testString = "abcd a"; + Pattern pat = Pattern.compile(baseString); + Matcher mat = pat.matcher(testString); + + assertTrue(mat.matches()); + } + + /* + * Verify if the Pattern support the following character classes: + * \p{javaLowerCase} \p{javaUpperCase} \p{javaWhitespace} \p{javaMirrored} + */ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) method.", + method = "compile", + args = {java.lang.String.class} + ) + public void testCompileCharacterClass() { + // Regression for HARMONY-606, 696 + Pattern pattern = Pattern.compile("\\p{javaLowerCase}"); + assertNotNull(pattern); + + pattern = Pattern.compile("\\p{javaUpperCase}"); + assertNotNull(pattern); + + pattern = Pattern.compile("\\p{javaWhitespace}"); + assertNotNull(pattern); + + pattern = Pattern.compile("\\p{javaMirrored}"); + assertNotNull(pattern); + + pattern = Pattern.compile("\\p{javaDefined}"); + assertNotNull(pattern); + + pattern = Pattern.compile("\\p{javaDigit}"); + assertNotNull(pattern); + + pattern = Pattern.compile("\\p{javaIdentifierIgnorable}"); + assertNotNull(pattern); + + pattern = Pattern.compile("\\p{javaISOControl}"); + assertNotNull(pattern); + + pattern = Pattern.compile("\\p{javaJavaIdentifierPart}"); + assertNotNull(pattern); + + pattern = Pattern.compile("\\p{javaJavaIdentifierStart}"); + assertNotNull(pattern); + + pattern = Pattern.compile("\\p{javaLetter}"); + assertNotNull(pattern); + + pattern = Pattern.compile("\\p{javaLetterOrDigit}"); + assertNotNull(pattern); + + pattern = Pattern.compile("\\p{javaSpaceChar}"); + assertNotNull(pattern); + + pattern = Pattern.compile("\\p{javaTitleCase}"); + assertNotNull(pattern); + + pattern = Pattern.compile("\\p{javaUnicodeIdentifierPart}"); + assertNotNull(pattern); + + pattern = Pattern.compile("\\p{javaUnicodeIdentifierStart}"); + assertNotNull(pattern); + } + + /** + * s original test was fixed to pass on RI + */ + +// BEGIN android-removed +// We don't have canonical equivalence. +// public void testCanonEqFlag() { +// +// /* +// * for decompositions see +// * http://www.unicode.org/Public/4.0-Update/UnicodeData-4.0.0.txt +// * http://www.unicode.org/reports/tr15/#Decomposition +// */ +// String baseString; +// String testString; +// Pattern pat; +// Matcher mat; +// +// baseString = "ab(a*)\\1"; +// pat = Pattern.compile(baseString, Pattern.CANON_EQ); +// +// baseString = "a(abcdf)d"; +// pat = Pattern.compile(baseString, Pattern.CANON_EQ); +// +// baseString = "aabcdfd"; +// pat = Pattern.compile(baseString, Pattern.CANON_EQ); +// +// // \u01E0 -> \u0226\u0304 ->\u0041\u0307\u0304 +// // \u00CC -> \u0049\u0300 +// +// /* +// * baseString = "\u01E0\u00CCcdb(ac)"; testString = +// * "\u0226\u0304\u0049\u0300cdbac"; pat = Pattern.compile(baseString, +// * Pattern.CANON_EQ); mat = pat.matcher(testString); +// * assertTrue(mat.matches()); +// */ +// baseString = "\u01E0cdb(a\u00CCc)"; +// testString = "\u0041\u0307\u0304cdba\u0049\u0300c"; +// pat = Pattern.compile(baseString, Pattern.CANON_EQ); +// mat = pat.matcher(testString); +// assertTrue(mat.matches()); +// +// baseString = "a\u00CC"; +// testString = "a\u0049\u0300"; +// pat = Pattern.compile(baseString, Pattern.CANON_EQ); +// mat = pat.matcher(testString); +// assertTrue(mat.matches()); +// +// /* +// * baseString = "\u0226\u0304cdb(ac\u0049\u0300)"; testString = +// * "\u01E0cdbac\u00CC"; pat = Pattern.compile(baseString, +// * Pattern.CANON_EQ); mat = pat.matcher(testString); +// * assertTrue(mat.matches()); +// * +// * baseString = "cdb(?:\u0041\u0307\u0304\u00CC)"; testString = +// * "cdb\u0226\u0304\u0049\u0300"; pat = Pattern.compile(baseString, +// * Pattern.CANON_EQ); mat = pat.matcher(testString); +// * assertTrue(mat.matches()); +// * +// * baseString = "\u01E0[a-c]\u0049\u0300cdb(ac)"; testString = +// * "\u01E0b\u00CCcdbac"; pat = Pattern.compile(baseString, +// * Pattern.CANON_EQ); mat = pat.matcher(testString); +// * assertTrue(mat.matches()); +// * +// * baseString = "\u01E0|\u00CCcdb(ac)"; testString = +// * "\u0041\u0307\u0304"; pat = Pattern.compile(baseString, +// * Pattern.CANON_EQ); mat = pat.matcher(testString); +// * assertTrue(mat.matches()); +// * +// * baseString = "\u00CC?cdb(ac)*(\u01E0)*[a-c]"; testString = +// * "cdb\u0041\u0307\u0304b"; pat = Pattern.compile(baseString, +// * Pattern.CANON_EQ); mat = pat.matcher(testString); +// * assertTrue(mat.matches()); +// */ +// baseString = "a\u0300"; +// pat = Pattern.compile(baseString, Pattern.CANON_EQ); +// mat = pat.matcher("a\u00E0a"); +// assertTrue(mat.find()); +// +// /* +// * baseString = "\u7B20\uF9F8abc"; pat = Pattern.compile(baseString, +// * Pattern.CANON_EQ); mat = pat.matcher("\uF9F8\uF9F8abc"); +// * assertTrue(mat.matches()); +// * +// * //\u01F9 -> \u006E\u0300 //\u00C3 -> \u0041\u0303 +// * +// * baseString = "cdb(?:\u00C3\u006E\u0300)"; testString = +// * "cdb\u0041\u0303\u01F9"; pat = Pattern.compile(baseString, +// * Pattern.CANON_EQ); mat = pat.matcher(testString); +// * assertTrue(mat.matches()); +// * +// * //\u014C -> \u004F\u0304 //\u0163 -> \u0074\u0327 +// * +// * baseString = "cdb(?:\u0163\u004F\u0304)"; testString = +// * "cdb\u0074\u0327\u014C"; pat = Pattern.compile(baseString, +// * Pattern.CANON_EQ); mat = pat.matcher(testString); +// * assertTrue(mat.matches()); +// */ +// // \u00E1->a\u0301 +// // canonical ordering takes place \u0301\u0327 -> \u0327\u0301 +// baseString = "c\u0327\u0301"; +// testString = "c\u0301\u0327"; +// pat = Pattern.compile(baseString, Pattern.CANON_EQ); +// mat = pat.matcher(testString); +// assertTrue(mat.matches()); +// +// /* +// * Hangul decompositions +// */ +// // \uD4DB->\u1111\u1171\u11B6 +// // \uD21E->\u1110\u116D\u11B5 +// // \uD264->\u1110\u1170 +// // not Hangul:\u0453->\u0433\u0301 +// baseString = "a\uD4DB\u1111\u1171\u11B6\uD264"; +// pat = Pattern.compile(baseString, Pattern.CANON_EQ); +// +// baseString = "\u0453c\uD4DB"; +// pat = Pattern.compile(baseString, Pattern.CANON_EQ); +// +// baseString = "a\u1110\u116D\u11B5b\uD21Ebc"; +// pat = Pattern.compile(baseString, Pattern.CANON_EQ); +// +// /* +// * baseString = "\uD4DB\uD21E\u1110\u1170cdb(ac)"; testString = +// * "\u1111\u1171\u11B6\u1110\u116D\u11B5\uD264cdbac"; pat = +// * Pattern.compile(baseString, Pattern.CANON_EQ); mat = +// * pat.matcher(testString); assertTrue(mat.matches()); +// */ +// baseString = "\uD4DB\uD264cdb(a\uD21Ec)"; +// testString = "\u1111\u1171\u11B6\u1110\u1170cdba\u1110\u116D\u11B5c"; +// pat = Pattern.compile(baseString, Pattern.CANON_EQ); +// mat = pat.matcher(testString); +// assertTrue(mat.matches()); +// +// baseString = "a\uD4DB"; +// testString = "a\u1111\u1171\u11B6"; +// pat = Pattern.compile(baseString, Pattern.CANON_EQ); +// mat = pat.matcher(testString); +// assertTrue(mat.matches()); +// +// baseString = "a\uD21E"; +// testString = "a\u1110\u116D\u11B5"; +// pat = Pattern.compile(baseString, Pattern.CANON_EQ); +// mat = pat.matcher(testString); +// assertTrue(mat.matches()); +// +// /* +// * baseString = "\u1111\u1171\u11B6cdb(ac\u1110\u116D\u11B5)"; +// * testString = "\uD4DBcdbac\uD21E"; pat = Pattern.compile(baseString, +// * Pattern.CANON_EQ); mat = pat.matcher(testString); +// * assertTrue(mat.matches()); +// * +// * baseString = "cdb(?:\u1111\u1171\u11B6\uD21E)"; testString = +// * "cdb\uD4DB\u1110\u116D\u11B5"; pat = Pattern.compile(baseString, +// * Pattern.CANON_EQ); mat = pat.matcher(testString); +// * assertTrue(mat.matches()); +// * +// * baseString = "\uD4DB[a-c]\u1110\u116D\u11B5cdb(ac)"; testString = +// * "\uD4DBb\uD21Ecdbac"; pat = Pattern.compile(baseString, +// * Pattern.CANON_EQ); mat = pat.matcher(testString); +// * assertTrue(mat.matches()); +// */ +// baseString = "\uD4DB|\u00CCcdb(ac)"; +// testString = "\u1111\u1171\u11B6"; +// pat = Pattern.compile(baseString, Pattern.CANON_EQ); +// mat = pat.matcher(testString); +// assertTrue(mat.matches()); +// +// baseString = "\uD4DB|\u00CCcdb(ac)"; +// testString = "\u1111\u1171"; +// pat = Pattern.compile(baseString, Pattern.CANON_EQ); +// mat = pat.matcher(testString); +// assertFalse(mat.matches()); +// +// baseString = "\u00CC?cdb(ac)*(\uD4DB)*[a-c]"; +// testString = "cdb\u1111\u1171\u11B6b"; +// pat = Pattern.compile(baseString, Pattern.CANON_EQ); +// mat = pat.matcher(testString); +// assertTrue(mat.matches()); +// +// baseString = "\uD4DB"; +// pat = Pattern.compile(baseString, Pattern.CANON_EQ); +// mat = pat.matcher("a\u1111\u1171\u11B6a"); +// assertTrue(mat.find()); +// +// baseString = "\u1111"; +// pat = Pattern.compile(baseString, Pattern.CANON_EQ); +// mat = pat.matcher("bcda\uD4DBr"); +// assertFalse(mat.find()); +// } +// +// /** +// * s original test was fixed to pass on RI +// */ +// +// public void testIndexesCanonicalEq() { +// String baseString; +// String testString; +// Pattern pat; +// Matcher mat; +// +// baseString = "\uD4DB"; +// pat = Pattern.compile(baseString, Pattern.CANON_EQ); +// mat = pat.matcher("bcda\u1111\u1171\u11B6awr"); +// assertTrue(mat.find()); +// assertEquals(mat.start(), 4); +// assertEquals(mat.end(), 7); +// +// /* +// * baseString = "\uD4DB\u1111\u1171\u11B6"; pat = +// * Pattern.compile(baseString, Pattern.CANON_EQ); mat = +// * pat.matcher("bcda\u1111\u1171\u11B6\uD4DBawr"); +// * assertTrue(mat.find()); assertEquals(mat.start(), 4); +// * assertEquals(mat.end(), 8); +// * +// * baseString = "\uD4DB\uD21E\u1110\u1170"; testString = +// * "abcabc\u1111\u1171\u11B6\u1110\u116D\u11B5\uD264cdbac"; pat = +// * Pattern.compile(baseString, Pattern.CANON_EQ); mat = +// * pat.matcher(testString); assertTrue(mat.find()); +// * assertEquals(mat.start(), 6); assertEquals(mat.end(), 13); +// */} +// +// /** +// * s original test was fixed to pass on RI +// */ +// +// public void testCanonEqFlagWithSupplementaryCharacters() { +// +// /* +// * \u1D1BF->\u1D1BB\u1D16F->\u1D1B9\u1D165\u1D16F in UTF32 +// * \uD834\uDDBF->\uD834\uDDBB\uD834\uDD6F +// * ->\uD834\uDDB9\uD834\uDD65\uD834\uDD6F in UTF16 +// */ +// String patString = "abc\uD834\uDDBFef"; +// String testString = "abc\uD834\uDDB9\uD834\uDD65\uD834\uDD6Fef"; +// Pattern pat = Pattern.compile(patString, Pattern.CANON_EQ); +// Matcher mat = pat.matcher(testString); +// assertTrue(mat.matches()); +// /* +// * testString = "abc\uD834\uDDBB\uD834\uDD6Fef"; mat = +// * pat.matcher(testString); assertTrue(mat.matches()); +// * +// * patString = "abc\uD834\uDDBB\uD834\uDD6Fef"; testString = +// * "abc\uD834\uDDBFef"; pat = Pattern.compile(patString, +// * Pattern.CANON_EQ); mat = pat.matcher(testString); +// * assertTrue(mat.matches()); +// */ +// testString = "abc\uD834\uDDB9\uD834\uDD65\uD834\uDD6Fef"; +// mat = pat.matcher(testString); +// assertTrue(mat.matches()); +// /* +// * patString = "abc\uD834\uDDB9\uD834\uDD65\uD834\uDD6Fef"; testString = +// * "abc\uD834\uDDBFef"; pat = Pattern.compile(patString, +// * Pattern.CANON_EQ); mat = pat.matcher(testString); +// * assertTrue(mat.matches()); +// * +// * testString = "abc\uD834\uDDBB\uD834\uDD6Fef"; mat = +// * pat.matcher(testString); assertTrue(mat.matches()); +// */ +// /* +// * testSupplementary characters with no decomposition +// */ +// /* +// * patString = "a\uD9A0\uDE8Ebc\uD834\uDDBB\uD834\uDD6Fe\uDE8Ef"; +// * testString = "a\uD9A0\uDE8Ebc\uD834\uDDBFe\uDE8Ef"; pat = +// * Pattern.compile(patString, Pattern.CANON_EQ); mat = +// * pat.matcher(testString); assertTrue(mat.matches()); +// */} +// END android-removed + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testRangesWithSurrogatesSupplementary() { + String patString = "[abc\uD8D2]"; + String testString = "\uD8D2"; + Pattern pat = Pattern.compile(patString); + Matcher mat = pat.matcher(testString); + assertTrue(mat.matches()); + + testString = "a"; + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + testString = "ef\uD8D2\uDD71gh"; + mat = pat.matcher(testString); + assertFalse(mat.find()); + + testString = "ef\uD8D2gh"; + mat = pat.matcher(testString); + assertTrue(mat.find()); + + patString = "[abc\uD8D3&&[c\uD8D3]]"; + testString = "c"; + pat = Pattern.compile(patString); + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + testString = "a"; + mat = pat.matcher(testString); + assertFalse(mat.matches()); + + testString = "ef\uD8D3\uDD71gh"; + mat = pat.matcher(testString); + assertFalse(mat.find()); + + testString = "ef\uD8D3gh"; + mat = pat.matcher(testString); + assertTrue(mat.find()); + + patString = "[abc\uD8D3\uDBEE\uDF0C&&[c\uD8D3\uDBEE\uDF0C]]"; + testString = "c"; + pat = Pattern.compile(patString); + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + testString = "\uDBEE\uDF0C"; + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + testString = "ef\uD8D3\uDD71gh"; + mat = pat.matcher(testString); + assertFalse(mat.find()); + + testString = "ef\uD8D3gh"; + mat = pat.matcher(testString); + assertTrue(mat.find()); + + patString = "[abc\uDBFC]\uDDC2cd"; + testString = "\uDBFC\uDDC2cd"; + pat = Pattern.compile(patString); + mat = pat.matcher(testString); + assertFalse(mat.matches()); + + testString = "a\uDDC2cd"; + mat = pat.matcher(testString); + assertTrue(mat.matches()); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testSequencesWithSurrogatesSupplementary() { + String patString = "abcd\uD8D3"; + String testString = "abcd\uD8D3\uDFFC"; + Pattern pat = Pattern.compile(patString); + Matcher mat = pat.matcher(testString); +// BEGIN android-changed +// This one really doesn't make sense, as the above is a corrupt surrogate. +// Even if it's matched by the JDK, it's more of a bug than of a behavior one +// might want to duplicate. +// assertFalse(mat.find()); +// END android-changed + testString = "abcd\uD8D3abc"; + mat = pat.matcher(testString); + assertTrue(mat.find()); + + patString = "ab\uDBEFcd"; + testString = "ab\uDBEFcd"; + pat = Pattern.compile(patString); + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + patString = "\uDFFCabcd"; + testString = "\uD8D3\uDFFCabcd"; + pat = Pattern.compile(patString); + mat = pat.matcher(testString); + assertFalse(mat.find()); + + testString = "abc\uDFFCabcdecd"; + mat = pat.matcher(testString); + assertTrue(mat.find()); + + patString = "\uD8D3\uDFFCabcd"; + testString = "abc\uD8D3\uD8D3\uDFFCabcd"; + pat = Pattern.compile(patString); + mat = pat.matcher(testString); + assertTrue(mat.find()); + } + + /** + * s original test was fixed to pass on RI + */ + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testPredefinedClassesWithSurrogatesSupplementary() { + String patString = "[123\\D]"; + String testString = "a"; + Pattern pat = Pattern.compile(patString); + Matcher mat = pat.matcher(testString); + assertTrue(mat.find()); + + testString = "5"; + mat = pat.matcher(testString); + assertFalse(mat.find()); + + testString = "3"; + mat = pat.matcher(testString); + assertTrue(mat.find()); + + // low surrogate + testString = "\uDFC4"; + mat = pat.matcher(testString); + assertTrue(mat.find()); + + // high surrogate + testString = "\uDADA"; + mat = pat.matcher(testString); + assertTrue(mat.find()); + + testString = "\uDADA\uDFC4"; + mat = pat.matcher(testString); + assertTrue(mat.find()); + + patString = "[123[^\\p{javaDigit}]]"; + testString = "a"; + pat = Pattern.compile(patString); + mat = pat.matcher(testString); + assertTrue(mat.find()); + + testString = "5"; + mat = pat.matcher(testString); + assertFalse(mat.find()); + + testString = "3"; + mat = pat.matcher(testString); + assertTrue(mat.find()); + + // low surrogate + testString = "\uDFC4"; + mat = pat.matcher(testString); + assertTrue(mat.find()); + + // high surrogate + testString = "\uDADA"; + mat = pat.matcher(testString); + assertTrue(mat.find()); + + testString = "\uDADA\uDFC4"; + mat = pat.matcher(testString); + assertTrue(mat.find()); + + // surrogate characters + patString = "\\p{Cs}"; + testString = "\uD916\uDE27"; + pat = Pattern.compile(patString); + mat = pat.matcher(testString); + + /* + * see http://www.unicode.org/reports/tr18/#Supplementary_Characters we + * have to treat text as code points not code units. \\p{Cs} matches any + * surrogate character but here testString is a one code point + * consisting of two code units (two surrogate characters) so we find + * nothing + */ + // assertFalse(mat.find()); + // swap low and high surrogates + testString = "\uDE27\uD916"; + mat = pat.matcher(testString); + assertTrue(mat.find()); + + patString = "[\uD916\uDE271\uD91623&&[^\\p{Cs}]]"; + testString = "1"; + pat = Pattern.compile(patString); + mat = pat.matcher(testString); + assertTrue(mat.find()); + + testString = "\uD916"; + pat = Pattern.compile(patString); + mat = pat.matcher(testString); + assertFalse(mat.find()); + + testString = "\uD916\uDE27"; + pat = Pattern.compile(patString); + mat = pat.matcher(testString); + assertTrue(mat.find()); + + // \uD9A0\uDE8E=\u7828E + // \u78281=\uD9A0\uDE81 + patString = "[a-\uD9A0\uDE8E]"; + testString = "\uD9A0\uDE81"; + pat = Pattern.compile(patString); + mat = pat.matcher(testString); + assertTrue(mat.matches()); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & compile(java.lang.String, int) matcher(java.lang.CharSequence) methods.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & compile(java.lang.String, int) matcher(java.lang.CharSequence) methods.", + method = "compile", + args = {java.lang.String.class, int.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & compile(java.lang.String, int) matcher(java.lang.CharSequence) methods.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testDotConstructionWithSurrogatesSupplementary() { + String patString = "."; + String testString = "\uD9A0\uDE81"; + Pattern pat = Pattern.compile(patString); + Matcher mat = pat.matcher(testString); + assertTrue(mat.matches()); + + testString = "\uDE81"; + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + testString = "\uD9A0"; + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + testString = "\n"; + mat = pat.matcher(testString); + assertFalse(mat.matches()); + + patString = ".*\uDE81"; + testString = "\uD9A0\uDE81\uD9A0\uDE81\uD9A0\uDE81"; + pat = Pattern.compile(patString); + mat = pat.matcher(testString); + assertFalse(mat.matches()); + + testString = "\uD9A0\uDE81\uD9A0\uDE81\uDE81"; + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + patString = ".*"; + testString = "\uD9A0\uDE81\n\uD9A0\uDE81\uD9A0\n\uDE81"; + pat = Pattern.compile(patString, Pattern.DOTALL); + mat = pat.matcher(testString); + assertTrue(mat.matches()); + } + + /** + * s java.util.regex.Pattern.quote(String) + */ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "", + method = "quote", + args = {java.lang.String.class} + ) + public void test_quoteLjava_lang_String() { + for (String aPattern : testPatterns) { + Pattern p = Pattern.compile(aPattern); + try { + assertEquals("quote was wrong for plain text", "\\Qtest\\E", p + .quote("test")); + assertEquals("quote was wrong for text with quote sign", + "\\Q\\Qtest\\E", p.quote("\\Qtest")); + assertEquals("quote was wrong for quotted text", + "\\Q\\Qtest\\E\\\\E\\Q\\E", p.quote("\\Qtest\\E")); + } catch (Exception e) { + fail("Unexpected exception: " + e); + } + } + } + + /** + * s java.util.regex.Pattern.matcher(String, CharSequence) + * coped from test for matches method + */ + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void test_matcherLjava_lang_StringLjava_lang_CharSequence() { + String[][] posSeq = { + { "abb", "ababb", "abababbababb", "abababbababbabababbbbbabb" }, + { "213567", "12324567", "1234567", "213213567", + "21312312312567", "444444567" }, + { "abcdaab", "aab", "abaab", "cdaab", "acbdadcbaab" }, + { "213234567", "3458", "0987654", "7689546432", "0398576", + "98432", "5" }, + { + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" }, + { "ababbaAabababblice", "ababbaAliceababab", "ababbAabliceaaa", + "abbbAbbbliceaaa", "Alice" }, + { "a123", "bnxnvgds156", "for", "while", "if", "struct" }, + { "xy" }, { "xy" }, { "xcy" } + + }; + + for (int i = 0; i < testPatterns.length; i++) { + for (int j = 0; j < posSeq[i].length; j++) { + assertTrue("Incorrect match: " + testPatterns[i] + " vs " + + posSeq[i][j], Pattern.compile(testPatterns[i]) + .matcher(posSeq[i][j]).matches()); + } + } + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testQuantifiersWithSurrogatesSupplementary() { + String patString = "\uD9A0\uDE81*abc"; + String testString = "\uD9A0\uDE81\uD9A0\uDE81abc"; + Pattern pat = Pattern.compile(patString); + Matcher mat = pat.matcher(testString); + assertTrue(mat.matches()); + + testString = "abc"; + mat = pat.matcher(testString); + assertTrue(mat.matches()); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testAlternationsWithSurrogatesSupplementary() { + String patString = "\uDE81|\uD9A0\uDE81|\uD9A0"; + String testString = "\uD9A0"; + Pattern pat = Pattern.compile(patString); + Matcher mat = pat.matcher(testString); + assertTrue(mat.matches()); + + testString = "\uDE81"; + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + testString = "\uD9A0\uDE81"; + mat = pat.matcher(testString); + assertTrue(mat.matches()); + + testString = "\uDE81\uD9A0"; + mat = pat.matcher(testString); + assertFalse(mat.matches()); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & compile(java.lang.String, int) & matcher(java.lang.CharSequence) methods.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & compile(java.lang.String, int) & matcher(java.lang.CharSequence) methods.", + method = "compile", + args = {java.lang.String.class, int.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of compile(java.lang.String) & compile(java.lang.String, int) & matcher(java.lang.CharSequence) methods.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testGroupsWithSurrogatesSupplementary() { + + //this pattern matches nothing + String patString = "(\uD9A0)\uDE81"; + String testString = "\uD9A0\uDE81"; + Pattern pat = Pattern.compile(patString); + Matcher mat = pat.matcher(testString); + assertFalse(mat.matches()); + + patString = "(\uD9A0)"; + testString = "\uD9A0\uDE81"; + pat = Pattern.compile(patString, Pattern.DOTALL); + mat = pat.matcher(testString); + assertFalse(mat.find()); + } + + /* + * Regression test for HARMONY-688 + */ + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "The test verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "compile", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "The test verifies the functionality of compile(java.lang.String) & matcher(java.lang.CharSequence) methods.", + method = "matcher", + args = {java.lang.CharSequence.class} + ) + }) + public void testUnicodeCategoryWithSurrogatesSupplementary() { + Pattern p = Pattern.compile("\\p{javaLowerCase}"); + Matcher matcher = p.matcher("\uD801\uDC28"); + assertTrue(matcher.find()); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(PatternTest.class); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "The test doesn't verify Matcher and should be moved to PatterTest.", + method = "split", + args = {java.lang.CharSequence.class, int.class} + ) + public void testSplitEmpty() { + + Pattern pat = Pattern.compile(""); + String[] s = pat.split("", -1); + + assertEquals(1, s.length); + assertEquals("", s[0]); + } + + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "", + method = "toString", + args = {} + ) + public void testToString() { + for (int i = 0; i < testPatterns.length; i++) { + Pattern p = Pattern.compile(testPatterns[i]); + assertEquals(testPatterns[i], p.toString()); + } + } + +} diff --git a/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/ReplaceTest.java b/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/ReplaceTest.java new file mode 100644 index 0000000..82390e7 --- /dev/null +++ b/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/ReplaceTest.java @@ -0,0 +1,125 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.harmony.regex.tests.java.util.regex; + +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestLevel; + +import junit.framework.TestCase; +import java.util.regex.Pattern; +import java.util.regex.Matcher; +import java.util.regex.PatternSyntaxException; + +@TestTargetClass(Matcher.class) +public class ReplaceTest extends TestCase { + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the basic functionality of replaceFirst(java.lang.String) & replaceAll(java.lang.String) methods.", + method = "replaceFirst", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the basic functionality of replaceFirst(java.lang.String) & replaceAll(java.lang.String) methods.", + method = "replaceAll", + args = {java.lang.String.class} + ) + }) + public void testSimpleReplace() throws PatternSyntaxException { + String target, pattern, repl; + + target = "foobarfobarfoofo1barfort"; + pattern = "fo[^o]"; + repl = "xxx"; + + Pattern p = Pattern.compile(pattern); + Matcher m = p.matcher(target); + + assertEquals("foobarxxxarfoofo1barfort", m.replaceFirst(repl)); + assertEquals("foobarxxxarfooxxxbarxxxt", m.replaceAll(repl)); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of replaceFirst(java.lang.String) & replaceAll(java.lang.String) methods.", + method = "replaceFirst", + args = {java.lang.String.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of replaceFirst(java.lang.String) & replaceAll(java.lang.String) methods.", + method = "replaceAll", + args = {java.lang.String.class} + ) + }) + public void testCaptureReplace() { + String target, pattern, repl, s; + Pattern p = null; + Matcher m; + + target = "[31]foo;bar[42];[99]xyz"; + pattern = "\\[([0-9]+)\\]([a-z]+)"; + repl = "$2[$1]"; + + p = Pattern.compile(pattern); + m = p.matcher(target); + s = m.replaceFirst(repl); + assertEquals("foo[31];bar[42];[99]xyz", s); + s = m.replaceAll(repl); + assertEquals("foo[31];bar[42];xyz[99]", s); + + target = "[31]foo(42)bar{63}zoo;[12]abc(34)def{56}ghi;{99}xyz[88]xyz(77)xyz;"; + pattern = "\\[([0-9]+)\\]([a-z]+)\\(([0-9]+)\\)([a-z]+)\\{([0-9]+)\\}([a-z]+)"; + repl = "[$5]$6($3)$4{$1}$2"; + p = Pattern.compile(pattern); + m = p.matcher(target); + s = m.replaceFirst(repl); + // System.out.println(s); + assertEquals("[63]zoo(42)bar{31}foo;[12]abc(34)def{56}ghi;{99}xyz[88]xyz(77)xyz;", s + ); + s = m.replaceAll(repl); + // System.out.println(s); + assertEquals("[63]zoo(42)bar{31}foo;[56]ghi(34)def{12}abc;{99}xyz[88]xyz(77)xyz;", s + ); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of replaceAll(java.lang.String) method with backslash chars.", + method = "replaceAll", + args = {java.lang.String.class} + ) + public void testEscapeReplace() { + String target, pattern, repl, s; + + target = "foo'bar''foo"; + pattern = "'"; + repl = "\\'"; + s = target.replaceAll(pattern, repl); + assertEquals("foo'bar''foo", s); + repl = "\\\\'"; + s = target.replaceAll(pattern, repl); + assertEquals("foo\\'bar\\'\\'foo", s); + repl = "\\$3"; + s = target.replaceAll(pattern, repl); + assertEquals("foo$3bar$3$3foo", s); + } +} diff --git a/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/SplitTest.java b/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/SplitTest.java new file mode 100644 index 0000000..ea615c0 --- /dev/null +++ b/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/SplitTest.java @@ -0,0 +1,201 @@ +package org.apache.harmony.regex.tests.java.util.regex; + +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.TestTargets; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestLevel; + +import junit.framework.TestCase; +import java.util.regex.*; + +@TestTargetClass(java.util.regex.Pattern.class) +/** + * TODO Type description + * + */ +public class SplitTest extends TestCase { + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the basic functionality of split(java.lang.CharSequence) & compile(java.lang.String)methods.", + method = "split", + args = {java.lang.CharSequence.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the basic functionality of split(java.lang.CharSequence) & compile(java.lang.String)methods.", + method = "compile", + args = {java.lang.String.class} + ) + }) + public void testSimple() { + Pattern p = Pattern.compile("/"); + String[] results = p.split("have/you/done/it/right"); + String[] expected = new String[] { "have", "you", "done", "it", "right" }; + assertEquals(expected.length, results.length); + for (int i = 0; i < expected.length; i++) { + assertEquals(results[i], expected[i]); + } + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of split(java.lang.CharSequence). Test uses not empty pattern.", + method = "split", + args = {java.lang.CharSequence.class, int.class} + ) + public void testSplit1() throws PatternSyntaxException { + Pattern p = Pattern.compile(" "); + + String input = "poodle zoo"; + String tokens[]; + + tokens = p.split(input, 1); + assertEquals(1, tokens.length); + assertTrue(tokens[0].equals(input)); + tokens = p.split(input, 2); + assertEquals(2, tokens.length); + assertEquals("poodle", tokens[0]); + assertEquals("zoo", tokens[1]); + tokens = p.split(input, 5); + assertEquals(2, tokens.length); + assertEquals("poodle", tokens[0]); + assertEquals("zoo", tokens[1]); + tokens = p.split(input, -2); + assertEquals(2, tokens.length); + assertEquals("poodle", tokens[0]); + assertEquals("zoo", tokens[1]); + tokens = p.split(input, 0); + assertEquals(2, tokens.length); + assertEquals("poodle", tokens[0]); + assertEquals("zoo", tokens[1]); + tokens = p.split(input); + assertEquals(2, tokens.length); + assertEquals("poodle", tokens[0]); + assertEquals("zoo", tokens[1]); + + p = Pattern.compile("d"); + + tokens = p.split(input, 1); + assertEquals(1, tokens.length); + assertTrue(tokens[0].equals(input)); + tokens = p.split(input, 2); + assertEquals(2, tokens.length); + assertEquals("poo", tokens[0]); + assertEquals("le zoo", tokens[1]); + tokens = p.split(input, 5); + assertEquals(2, tokens.length); + assertEquals("poo", tokens[0]); + assertEquals("le zoo", tokens[1]); + tokens = p.split(input, -2); + assertEquals(2, tokens.length); + assertEquals("poo", tokens[0]); + assertEquals("le zoo", tokens[1]); + tokens = p.split(input, 0); + assertEquals(2, tokens.length); + assertEquals("poo", tokens[0]); + assertEquals("le zoo", tokens[1]); + tokens = p.split(input); + assertEquals(2, tokens.length); + assertEquals("poo", tokens[0]); + assertEquals("le zoo", tokens[1]); + + p = Pattern.compile("o"); + + tokens = p.split(input, 1); + assertEquals(1, tokens.length); + assertTrue(tokens[0].equals(input)); + tokens = p.split(input, 2); + assertEquals(2, tokens.length); + assertEquals("p", tokens[0]); + assertEquals("odle zoo", tokens[1]); + tokens = p.split(input, 5); + assertEquals(5, tokens.length); + assertEquals("p", tokens[0]); + assertTrue(tokens[1].equals("")); + assertEquals("dle z", tokens[2]); + assertTrue(tokens[3].equals("")); + assertTrue(tokens[4].equals("")); + tokens = p.split(input, -2); + assertEquals(5, tokens.length); + assertEquals("p", tokens[0]); + assertTrue(tokens[1].equals("")); + assertEquals("dle z", tokens[2]); + assertTrue(tokens[3].equals("")); + assertTrue(tokens[4].equals("")); + tokens = p.split(input, 0); + assertEquals(3, tokens.length); + assertEquals("p", tokens[0]); + assertTrue(tokens[1].equals("")); + assertEquals("dle z", tokens[2]); + tokens = p.split(input); + assertEquals(3, tokens.length); + assertEquals("p", tokens[0]); + assertTrue(tokens[1].equals("")); + assertEquals("dle z", tokens[2]); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of split(java.lang.CharSequence). Test uses empty pattern.", + method = "split", + args = {java.lang.CharSequence.class, int.class} + ) + public void testSplit2() { + Pattern p = Pattern.compile(""); + String s[]; + s = p.split("a", -1); + assertEquals(3, s.length); + assertEquals("", s[0]); + assertEquals("a", s[1]); + assertEquals("", s[2]); + + s = p.split("", -1); + assertEquals(1, s.length); + assertEquals("", s[0]); + + s = p.split("abcd", -1); + assertEquals(6, s.length); + assertEquals("", s[0]); + assertEquals("a", s[1]); + assertEquals("b", s[2]); + assertEquals("c", s[3]); + assertEquals("d", s[4]); + assertEquals("", s[5]); + + // Regression test for Android + assertEquals("GOOG,23,500".split("|").length, 12); + } + + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of split(java.lang.CharSequence) & compile(java.lang.String, int) methods. Test uses empty pattern and supplementary chars.", + method = "split", + args = {java.lang.CharSequence.class, int.class} + ), + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the functionality of split(java.lang.CharSequence) & compile(java.lang.String, int) methods. Test uses empty pattern and supplementary chars.", + method = "compile", + args = {java.lang.String.class} + ) + }) + public void testSplitSupplementaryWithEmptyString() { + + /* + * See http://www.unicode.org/reports/tr18/#Supplementary_Characters + * We have to treat text as code points not code units. + */ + Pattern p = Pattern.compile(""); + String s[]; + s = p.split("a\ud869\uded6b", -1); + assertEquals(5, s.length); + assertEquals("", s[0]); + assertEquals("a", s[1]); + assertEquals("\ud869\uded6", s[2]); + assertEquals("b", s[3]); + assertEquals("", s[4]); + } +} diff --git a/regex/src/test/java/tests/regex/AllTests.java b/regex/src/test/java/tests/regex/AllTests.java new file mode 100644 index 0000000..d590d08 --- /dev/null +++ b/regex/src/test/java/tests/regex/AllTests.java @@ -0,0 +1,38 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package tests.regex; + +import junit.framework.Test; +import junit.framework.TestSuite; + +/** + * Test suite that includes all tests for the regex project. + */ +public class AllTests { + + public static void main(String[] args) { + junit.textui.TestRunner.run(AllTests.suite()); + } + + public static Test suite() { + TestSuite suite = tests.TestSuiteFactory.createTestSuite("All regex test suites"); + // $JUnit-BEGIN$ + suite.addTest(org.apache.harmony.regex.tests.java.util.regex.AllTests.suite()); + // $JUnit-END$ + return suite; + } +} diff --git a/regex/src/test/resources/serialization/org/apache/harmony/regex/tests/java/util/regex/PatternSyntaxExceptionTest.golden.ser b/regex/src/test/resources/serialization/org/apache/harmony/regex/tests/java/util/regex/PatternSyntaxExceptionTest.golden.ser Binary files differnew file mode 100755 index 0000000..623d6ac --- /dev/null +++ b/regex/src/test/resources/serialization/org/apache/harmony/regex/tests/java/util/regex/PatternSyntaxExceptionTest.golden.ser diff --git a/regex/src/test/resources/serialization/org/apache/harmony/regex/tests/java/util/regex/PatternTest.golden.ser b/regex/src/test/resources/serialization/org/apache/harmony/regex/tests/java/util/regex/PatternTest.golden.ser Binary files differnew file mode 100755 index 0000000..6150adf --- /dev/null +++ b/regex/src/test/resources/serialization/org/apache/harmony/regex/tests/java/util/regex/PatternTest.golden.ser |