diff -r 33423ec519fd -r 80ea8d3d39d0 jdk/test/java/util/regex/PatternStreamTest.java --- a/jdk/test/java/util/regex/PatternStreamTest.java Tue Mar 03 10:30:44 2015 +0300 +++ b/jdk/test/java/util/regex/PatternStreamTest.java Tue Mar 03 12:30:48 2015 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015 Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,8 +23,8 @@ /** * @test - * @bug 8016846 8024341 - * @summary Unit tests for wrapping classes should delegate to default methods + * @bug 8016846 8024341 8071479 + * @summary Unit tests stream and lambda-based methods on Pattern and Matcher * @library ../stream/bootlib * @build java.util.stream.OpTestCase * @run testng/othervm PatternStreamTest @@ -34,158 +34,283 @@ import org.testng.annotations.Test; import java.util.ArrayList; +import java.util.Arrays; +import java.util.ConcurrentModificationException; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Supplier; +import java.util.regex.MatchResult; +import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.LambdaTestHelpers; import java.util.stream.OpTestCase; import java.util.stream.Stream; import java.util.stream.TestData; +import static org.testng.Assert.*; + @Test public class PatternStreamTest extends OpTestCase { - @DataProvider(name = "Stream") + @DataProvider(name = "Patterns") public static Object[][] makeStreamTestData() { + // Each item must match the type signature of the consumer of this data + // String, String, Pattern List data = new ArrayList<>(); - String description = ""; - String input = "awgqwefg1fefw4vssv1vvv1"; - Pattern pattern = Pattern.compile("4"); - List expected = new ArrayList<>(); - expected.add("awgqwefg1fefw"); - expected.add("vssv1vvv1"); + String description = "All matches"; + String input = "XXXXXX"; + Pattern pattern = Pattern.compile("X"); + data.add(new Object[]{description, input, pattern}); + + description = "Bounded every other match"; + input = "XYXYXYYXYX"; + pattern = Pattern.compile("X"); + data.add(new Object[]{description, input, pattern}); - // Must match the type signature of the consumer of this data, testStrings - // String, String, Pattern, List - data.add(new Object[]{description, input, pattern, expected}); + description = "Every other match"; + input = "YXYXYXYYXYXY"; + pattern = Pattern.compile("X"); + data.add(new Object[]{description, input, pattern}); + + description = ""; + input = "awgqwefg1fefw4vssv1vvv1"; + pattern = Pattern.compile("4"); + data.add(new Object[]{description, input, pattern}); input = "afbfq\u00a3abgwgb\u00a3awngnwggw\u00a3a\u00a3ahjrnhneerh"; pattern = Pattern.compile("\u00a3a"); - expected = new ArrayList<>(); - expected.add("afbfq"); - expected.add("bgwgb"); - expected.add("wngnwggw"); - expected.add(""); - expected.add("hjrnhneerh"); - - data.add(new Object[]{description, input, pattern, expected}); - + data.add(new Object[]{description, input, pattern}); input = "awgqwefg1fefw4vssv1vvv1"; pattern = Pattern.compile("1"); - expected = new ArrayList<>(); - expected.add("awgqwefg"); - expected.add("fefw4vssv"); - expected.add("vvv"); - - data.add(new Object[]{description, input, pattern, expected}); - + data.add(new Object[]{description, input, pattern}); input = "a\u4ebafg1fefw\u4eba4\u9f9cvssv\u9f9c1v\u672c\u672cvv"; pattern = Pattern.compile("1"); - expected = new ArrayList<>(); - expected.add("a\u4ebafg"); - expected.add("fefw\u4eba4\u9f9cvssv\u9f9c"); - expected.add("v\u672c\u672cvv"); - - data.add(new Object[]{description, input, pattern, expected}); - + data.add(new Object[]{description, input, pattern}); input = "1\u56da23\u56da456\u56da7890"; pattern = Pattern.compile("\u56da"); - expected = new ArrayList<>(); - expected.add("1"); - expected.add("23"); - expected.add("456"); - expected.add("7890"); - - data.add(new Object[]{description, input, pattern, expected}); - + data.add(new Object[]{description, input, pattern}); input = "1\u56da23\u9f9c\u672c\u672c\u56da456\u56da\u9f9c\u672c7890"; pattern = Pattern.compile("\u56da"); - expected = new ArrayList<>(); - expected.add("1"); - expected.add("23\u9f9c\u672c\u672c"); - expected.add("456"); - expected.add("\u9f9c\u672c7890"); - - data.add(new Object[]{description, input, pattern, expected}); - + data.add(new Object[]{description, input, pattern}); description = "Empty input"; input = ""; pattern = Pattern.compile("\u56da"); - expected = new ArrayList<>(); - expected.add(""); - - data.add(new Object[]{description, input, pattern, expected}); - + data.add(new Object[]{description, input, pattern}); description = "Empty input with empty pattern"; input = ""; pattern = Pattern.compile(""); - expected = new ArrayList<>(); - expected.add(""); - - data.add(new Object[]{description, input, pattern, expected}); - + data.add(new Object[]{description, input, pattern}); description = "Multiple separators"; input = "This is,testing: with\tdifferent separators."; pattern = Pattern.compile("[ \t,:.]"); - expected = new ArrayList<>(); - expected.add("This"); - expected.add("is"); - expected.add("testing"); - expected.add(""); - expected.add("with"); - expected.add("different"); - expected.add("separators"); - + data.add(new Object[]{description, input, pattern}); description = "Repeated separators within and at end"; input = "boo:and:foo"; pattern = Pattern.compile("o"); - expected = new ArrayList<>(); - expected.add("b"); - expected.add(""); - expected.add(":and:f"); - + data.add(new Object[]{description, input, pattern}); description = "Many repeated separators within and at end"; input = "booooo:and:fooooo"; pattern = Pattern.compile("o"); - expected = new ArrayList<>(); - expected.add("b"); - expected.add(""); - expected.add(""); - expected.add(""); - expected.add(""); - expected.add(":and:f"); + data.add(new Object[]{description, input, pattern}); description = "Many repeated separators before last match"; input = "fooooo:"; pattern = Pattern.compile("o"); - expected = new ArrayList<>(); - expected.add("f"); - expected.add(""); - expected.add(""); - expected.add(""); - expected.add(""); - expected.add(":"); + data.add(new Object[] {description, input, pattern}); - data.add(new Object[] {description, input, pattern, expected}); return data.toArray(new Object[0][]); } - @Test(dataProvider = "Stream") - public void testStrings(String description, String input, Pattern pattern, List expected) { + @Test(dataProvider = "Patterns") + public void testPatternSplitAsStream(String description, String input, Pattern pattern) { + // Derive expected result from pattern.split + List expected = Arrays.asList(pattern.split(input)); + Supplier> ss = () -> pattern.splitAsStream(input); withData(TestData.Factory.ofSupplier(description, ss)) .stream(LambdaTestHelpers.identity()) .expectedResult(expected) .exercise(); } + + @Test(dataProvider = "Patterns") + public void testReplaceFirst(String description, String input, Pattern pattern) { + // Derive expected result from Matcher.replaceFirst(String ) + String expected = pattern.matcher(input).replaceFirst("R"); + String actual = pattern.matcher(input).replaceFirst(r -> "R"); + assertEquals(actual, expected); + } + + @Test(dataProvider = "Patterns") + public void testReplaceAll(String description, String input, Pattern pattern) { + // Derive expected result from Matcher.replaceAll(String ) + String expected = pattern.matcher(input).replaceAll("R"); + String actual = pattern.matcher(input).replaceAll(r -> "R"); + assertEquals(actual, expected); + + // Derive expected result from Matcher.find + Matcher m = pattern.matcher(input); + int expectedMatches = 0; + while (m.find()) { + expectedMatches++; + } + AtomicInteger actualMatches = new AtomicInteger(); + pattern.matcher(input).replaceAll(r -> "R" + actualMatches.incrementAndGet()); + assertEquals(expectedMatches, actualMatches.get()); + } + + @Test(dataProvider = "Patterns") + public void testMatchResults(String description, String input, Pattern pattern) { + // Derive expected result from Matcher.find + Matcher m = pattern.matcher(input); + List expected = new ArrayList<>(); + while (m.find()) { + expected.add(new MatchResultHolder(m)); + } + + Supplier> ss = () -> pattern.matcher(input).results(); + withData(TestData.Factory.ofSupplier(description, ss)) + .stream(s -> s.map(MatchResultHolder::new)) + .expectedResult(expected) + .exercise(); + } + + public void testFailfastMatchResults() { + Pattern p = Pattern.compile("X"); + Matcher m = p.matcher("XX"); + + Stream s = m.results(); + m.find(); + // Should start on the second match + assertEquals(s.count(), 1); + + // Fail fast without short-circuit + // Exercises Iterator.forEachRemaining + m.reset(); + try { + m.results().peek(mr -> m.reset()).count(); + fail(); + } catch (ConcurrentModificationException e) { + // Should reach here + } + + m.reset(); + try { + m.results().peek(mr -> m.find()).count(); + fail(); + } catch (ConcurrentModificationException e) { + // Should reach here + } + + // Fail fast with short-circuit + // Exercises Iterator.hasNext/next + m.reset(); + try { + m.results().peek(mr -> m.reset()).limit(2).count(); + fail(); + } catch (ConcurrentModificationException e) { + // Should reach here + } + + m.reset(); + try { + m.results().peek(mr -> m.find()).limit(2).count(); + fail(); + } catch (ConcurrentModificationException e) { + // Should reach here + } + } + + public void testFailfastReplace() { + Pattern p = Pattern.compile("X"); + Matcher m = p.matcher("XX"); + + // Fail fast without short-circuit + // Exercises Iterator.forEachRemaining + m.reset(); + try { + m.replaceFirst(mr -> { m.reset(); return "Y"; }); + fail(); + } catch (ConcurrentModificationException e) { + // Should reach here + } + + m.reset(); + try { + m.replaceAll(mr -> { m.reset(); return "Y"; }); + fail(); + } catch (ConcurrentModificationException e) { + // Should reach here + } + } + + // A holder of MatchResult that can compare + static class MatchResultHolder implements Comparable { + final MatchResult mr; + + MatchResultHolder(Matcher m) { + this(m.toMatchResult()); + } + + MatchResultHolder(MatchResult mr) { + this.mr = mr; + } + + @Override + public int compareTo(MatchResultHolder that) { + int c = that.mr.group().compareTo(this.mr.group()); + if (c != 0) + return c; + + c = Integer.compare(that.mr.start(), this.mr.start()); + if (c != 0) + return c; + + c = Integer.compare(that.mr.end(), this.mr.end()); + if (c != 0) + return c; + + c = Integer.compare(that.mr.groupCount(), this.mr.groupCount()); + if (c != 0) + return c; + + for (int g = 0; g < this.mr.groupCount(); g++) { + c = that.mr.group(g).compareTo(this.mr.group(g)); + if (c != 0) + return c; + + c = Integer.compare(that.mr.start(g), this.mr.start(g)); + if (c != 0) + return c; + + c = Integer.compare(that.mr.end(g), this.mr.end(g)); + if (c != 0) + return c; + } + return 0; + } + + @Override + public boolean equals(Object that) { + if (this == that) return true; + if (that == null || getClass() != that.getClass()) return false; + + return this.compareTo((MatchResultHolder) that) == 0; + } + + @Override + public int hashCode() { + return mr.group().hashCode(); + } + } }