From ffe4923e76686f6a0dcde7bbf93196eb57469fb8 Mon Sep 17 00:00:00 2001 From: Arnauld Date: Sun, 11 Mar 2012 11:08:13 +0100 Subject: [PATCH] add hamcrest-test-patterns in repo --- ...t-text-patterns-0.0.1-SNAPSHOT-sources.zip | Bin 0 -> 14477 bytes .../hamcrest-text-patterns-0.0.1-SNAPSHOT.jar | Bin 0 -> 19056 bytes .../hamcrest-text-patterns/README.markdown | 385 ++++++++++++++++++ 3 files changed, 385 insertions(+) create mode 100644 repo/org/hamcrest/hamcrest-text-patterns/0.0.1-SNAPSHOT/hamcrest-text-patterns-0.0.1-SNAPSHOT-sources.zip create mode 100644 repo/org/hamcrest/hamcrest-text-patterns/0.0.1-SNAPSHOT/hamcrest-text-patterns-0.0.1-SNAPSHOT.jar create mode 100644 repo/org/hamcrest/hamcrest-text-patterns/README.markdown diff --git a/repo/org/hamcrest/hamcrest-text-patterns/0.0.1-SNAPSHOT/hamcrest-text-patterns-0.0.1-SNAPSHOT-sources.zip b/repo/org/hamcrest/hamcrest-text-patterns/0.0.1-SNAPSHOT/hamcrest-text-patterns-0.0.1-SNAPSHOT-sources.zip new file mode 100644 index 0000000000000000000000000000000000000000..d6a820de72ebf7221a27803aca89859d131dad5b GIT binary patch literal 14477 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 literal 0 HcmV?d00001 diff --git a/repo/org/hamcrest/hamcrest-text-patterns/0.0.1-SNAPSHOT/hamcrest-text-patterns-0.0.1-SNAPSHOT.jar b/repo/org/hamcrest/hamcrest-text-patterns/0.0.1-SNAPSHOT/hamcrest-text-patterns-0.0.1-SNAPSHOT.jar new file mode 100644 index 0000000000000000000000000000000000000000..fe636587c1a7df2e69f8b2eda748678d6d18bd65 GIT binary patch literal 19056 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℞nhfG<{`$2l{z+F_SB2 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 A library for writing readable, composable regular expression matchers that integrates cleanly with Hamcrest. + +# Features + +* Easier to read (although more long-winded) than regular expressions +* Named capture groups: captured text is identified by name, not by the index of the group. +* Composable: patterns can be easily combined into more complex patterns without worrying about breaking regex syntax or changing group identifiers. +* Refactoring friendly: patterns can be refactored with your favourite IDE. + +# Parsing + +Here's a simple example of using Hamcrest Text Patterns to parse date ranges, such as "12 Apr 1994 - 16 Mar 2005". + +We can define components of the final text pattern using the factory methods defined in the Patterns class: + +```java +PatternComponent month = either( + "jan", "feb", "mar", "apr", "may", "jun", + "jul", "aug", "sep", "oct", "nov", "dec"); + +PatternComponent digit = anyCharacterInCategory("Digit"); + +PatternComponent date = separatedBy(whitespace(), + capture("day", exactly(2, digit)), + capture("month", caseInsensitive(month)), + capture("year", exactly(4, digit))); +``` + +We can combine these into a PatternMatcher for matching date ranges: + +```java +PatternMatcher dateRange = new PatternMatcher(separatedBy(whitespace(), + capture("from", date), "-", capture("to", date))); +``` + +We can now parse date ranges from input text and extract the dates using the names of the capture groups we defined in the dateRange pattern: "from" and "to". + +```java +String input = "31 Dec 2003 - 16 aug 2008"; + +Parse parse = dateRange.parse(input); + +assertThat(parse.get("from"), equalTo("31 Dec 2003")); +assertThat(parse.get("to"), equalTo("16 aug 2008")); +``` + +And, because we defined capture groups in our date pattern, we can extract the parts of the "from" and "to" dates: + +```java +assertThat(parse.get("from.day"), equalTo("31")); +assertThat(parse.get("from.month"), equalTo("Dec")); +assertThat(parse.get("from.year"), equalTo("2003")); + +assertThat(parse.get("to.day"), equalTo("16")); +assertThat(parse.get("to.month"), equalTo("aug")); +assertThat(parse.get("to.year"), equalTo("2008")); +``` + +# Matching + +A `PatternMatcher` is a Hamcrest matcher, and so text patterns can be used with libraries that build upon Hamcrest, such as JUnit or jMock. For example: + +```java +String input = "31 Dec 2003 - 16 aug 2008"; +assertThat(input, dateRange); + +String badInput = "31 12 2003 - 16 08 2008"; +assertThat(badInput, not(dateRange)); +``` + +# `PatternMatcherTests.java` + +```java +package org.hamcrest.text.pattern; + +import static org.hamcrest.core.IsNot.not; +import static org.hamcrest.text.pattern.PatternMatcher.matchesPattern; +import static org.hamcrest.text.pattern.Patterns.anyCharacter; +import static org.hamcrest.text.pattern.Patterns.anyCharacterIn; +import static org.hamcrest.text.pattern.Patterns.anyCharacterInCategory; +import static org.hamcrest.text.pattern.Patterns.anyCharacterNotIn; +import static org.hamcrest.text.pattern.Patterns.anyCharacterNotInCategory; +import static org.hamcrest.text.pattern.Patterns.capture; +import static org.hamcrest.text.pattern.Patterns.caseInsensitive; +import static org.hamcrest.text.pattern.Patterns.caseSensitive; +import static org.hamcrest.text.pattern.Patterns.either; +import static org.hamcrest.text.pattern.Patterns.exactly; +import static org.hamcrest.text.pattern.Patterns.from; +import static org.hamcrest.text.pattern.Patterns.listOf; +import static org.hamcrest.text.pattern.Patterns.oneOrMore; +import static org.hamcrest.text.pattern.Patterns.optional; +import static org.hamcrest.text.pattern.Patterns.separatedBy; +import static org.hamcrest.text.pattern.Patterns.sequence; +import static org.hamcrest.text.pattern.Patterns.text; +import static org.hamcrest.text.pattern.Patterns.valueOf; +import static org.hamcrest.text.pattern.Patterns.whitespace; +import static org.hamcrest.text.pattern.Patterns.zeroOrMore; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; + +import org.junit.Test; + +public class PatternMatcherTests { + @Test + public void matchesPlainText() { + PatternMatcher matcher = new PatternMatcher(text("text")); + + assertThat("text", matchesPattern(matcher)); + assertThat("xxxtextxxx", not(matchesPattern(matcher))); + assertThat("tex", not(matchesPattern(matcher))); + assertThat("blah", not(matchesPattern(matcher))); + } + + @Test + public void matchesPlainTextContainingSpecialRegexCharacters() { + assertThat("*star*", matchesPattern( + new PatternMatcher(text("*star*")))); + + assertThat("-", matchesPattern( + new PatternMatcher(text("-")))); + } + + @Test + public void matchesSequenceOfText() { + PatternMatcher matcher = new PatternMatcher(sequence("hello", " ", "world")); + + assertThat("hello world", matchesPattern(matcher)); + } + + @Test + public void matchesAlternatives() { + PatternMatcher matcher = new PatternMatcher(either(text("hello"), text("world"))); + + assertThat("hello", matchesPattern(matcher)); + assertThat("world", matchesPattern(matcher)); + assertThat("hello world", not(matchesPattern(matcher))); + } + + @Test + public void matchesOptionalPattern() { + PatternMatcher matcher = new PatternMatcher(sequence(text("hello"), optional(text(" world")))); + + assertThat("hello", matchesPattern(matcher)); + assertThat("hello world", matchesPattern(matcher)); + assertThat(" world", not(matchesPattern(matcher))); + } + + @Test + public void matchesRepetitionZeroOrMoreTimes() { + PatternMatcher matcher = new PatternMatcher(zeroOrMore(text("x"))); + + assertThat("", matchesPattern(matcher)); + assertThat("x", matchesPattern(matcher)); + assertThat("xxx", matchesPattern(matcher)); + assertThat(" xx", not(matchesPattern(matcher))); + assertThat("x x", not(matchesPattern(matcher))); + assertThat("xx ", not(matchesPattern(matcher))); + } + + @Test + public void matchesRepetitionOneOrMoreTimes() { + PatternMatcher matcher = new PatternMatcher(oneOrMore(text("x"))); + + assertThat("", not(matchesPattern(matcher))); + assertThat("x", matchesPattern(matcher)); + assertThat("xxx", matchesPattern(matcher)); + assertThat(" xx", not(matchesPattern(matcher))); + assertThat("x x", not(matchesPattern(matcher))); + assertThat("xx ", not(matchesPattern(matcher))); + } + + @Test + public void testCanMatchAnyCharacter() { + PatternMatcher matcher = new PatternMatcher(sequence(text("x"), anyCharacter(), text("y"))); + + assertThat("x.y", matchesPattern(matcher)); + assertThat("xzy", matchesPattern(matcher)); + assertThat("xy", not(matchesPattern(matcher))); + } + + @Test + public void testCapturesMatchedGroups() throws Exception { + PatternMatcher matcher = new PatternMatcher(sequence(capture("xs", oneOrMore(text("x"))), capture("ys", oneOrMore(text("y"))))); + + Parse parse; + + parse = matcher.parse("xxxyyy"); + assertEquals("xxx", parse.get("xs")); + assertEquals("yyy", parse.get("ys")); + + parse = matcher.parse("xxyyyyyy"); + assertEquals("xx", parse.get("xs")); + assertEquals("yyyyyy", parse.get("ys")); + } + + @Test + public void testFailsIfDoesNotMatchParseInput() { + PatternMatcher matcher = new PatternMatcher(text("expected input")); + + try { + matcher.parse("input that doesn't match"); + fail("should have thrown ParseException"); + } catch (PatternMatchException ex) { + // expected + } + } + + @Test + public void testCanReferToContentOfMatchedGroups() throws Exception { + PatternMatcher matcher = new PatternMatcher(sequence(capture("first", oneOrMore(text("x"))), text("-"), valueOf("first"))); + + assertThat("x-x", matchesPattern(matcher)); + assertThat("xx-xx", matchesPattern(matcher)); + + assertThat("x-xx", not(matchesPattern(matcher))); + assertThat("xx-x", not(matchesPattern(matcher))); + } + + PatternMatcher scopedMatcher = new PatternMatcher(sequence(capture("xs", oneOrMore(text("x"))), capture("inside", sequence(capture("xs", oneOrMore(text("X"))), valueOf("xs"))), valueOf("xs"))); + + @Test + public void testReferencesToGroupsAreLexicallyScoped() throws Exception { + assertThat("xxXXXXxx", matchesPattern(scopedMatcher)); + assertThat("xXXx", matchesPattern(scopedMatcher)); + assertThat("xXxx", not(matchesPattern(scopedMatcher))); + assertThat("xXXX", not(matchesPattern(scopedMatcher))); + } + + @Test + public void testNamesInInnerScopesCanBeQueriedUsingDottedPathNotation() throws Exception { + Parse parse = scopedMatcher.parse("xxXXXXXXxx"); + assertEquals("xx", parse.get("xs")); + assertEquals("XXX", parse.get("inside.xs")); + } + + @Test + public void testCanReferToValuesOfGroupsInInnerScopesUsingDottedPathNotation() { + PatternMatcher matcher = new PatternMatcher(sequence(capture("xs", oneOrMore(text("x"))), capture("inside", sequence(capture("xs", oneOrMore(text("X"))), valueOf("xs"))), valueOf("xs"), valueOf("inside.xs"))); + + assertThat("xXXXXxXX", matchesPattern(matcher)); + assertThat("xxXXxxX", matchesPattern(matcher)); + } + + @Test + public void testCanDefinePatternsInTermsOfExistingPatterns() { + PatternMatcher emailAddressMatcher = new PatternMatcher(sequence(capture("user", oneOrMore(anyCharacter())), "@", capture("host", oneOrMore(anyCharacter())))); + + PatternMatcher mailToURLMatcher = new PatternMatcher(sequence(capture("scheme", text("mailto")), ":", capture("email", emailAddressMatcher))); + + assertThat("mailto:npryce@users.sf.net", matchesPattern(mailToURLMatcher)); + } + + @Test + public void matchesCharacterInList() { + PatternMatcher matcher = new PatternMatcher(anyCharacterIn("0123456789")); + + for (int i = 0; i < 9; i++) { + String input = String.valueOf(i); + + assertThat(input, matchesPattern(matcher)); + } + assertThat("X", not(matchesPattern(matcher))); + } + + @Test + public void matchesCharacterRange() { + PatternMatcher matcher = new PatternMatcher(anyCharacterIn("0-9")); + + for (int i = 0; i < 9; i++) { + String input = String.valueOf(i); + + assertThat(input, matchesPattern(matcher)); + } + assertThat("X", not(matchesPattern(matcher))); + } + + @Test + public void matchesCharacterNotInRange() { + PatternMatcher matcher = new PatternMatcher(anyCharacterNotIn("0-9")); + + for (int i = 0; i < 9; i++) { + String input = String.valueOf(i); + + assertThat(input, not(matchesPattern(matcher))); + } + assertThat("X", matchesPattern(matcher)); + } + + @Test + public void matchesCharactersInUnicodeCategories() { + PatternMatcher matcher = new PatternMatcher(anyCharacterInCategory("Lu")); + + assertThat("A", matchesPattern(matcher)); + assertThat("a", not(matchesPattern(matcher))); + assertThat("B", matchesPattern(matcher)); + assertThat("b", not(matchesPattern(matcher))); + } + + @Test + public void matchesCharactersNotInUnicodeCategories() { + PatternMatcher matcher = new PatternMatcher(anyCharacterNotInCategory("Lu")); + + assertThat("A", not(matchesPattern(matcher))); + assertThat("a", matchesPattern(matcher)); + assertThat("B", not(matchesPattern(matcher))); + assertThat("b", matchesPattern(matcher)); + } + + @Test + public void matchesExactlyTheSpecifiedNumberOfRepetitions() { + PatternMatcher matcher = new PatternMatcher(exactly(3, "x")); + + assertThat("xx", not(matchesPattern(matcher))); + assertThat("xxx", matchesPattern(matcher)); + assertThat("xxxx", not(matchesPattern(matcher))); + } + + @Test + public void matchesARangeOfAllowableRepetitions() { + PatternMatcher matcher = new PatternMatcher(from(3, 5, "x")); + + assertThat("xx", not(matchesPattern(matcher))); + assertThat("xxx", matchesPattern(matcher)); + assertThat("xxxx", matchesPattern(matcher)); + assertThat("xxxxx", matchesPattern(matcher)); + assertThat("xxxxxx", not(matchesPattern(matcher))); + } + + @Test + public void matchesAListOfMatchedThings() { + PatternMatcher matcher = new PatternMatcher(listOf("x")); + + assertThat("", matchesPattern(matcher)); + assertThat("x", matchesPattern(matcher)); + assertThat("x,x", matchesPattern(matcher)); + assertThat("x,x,x,x,x", matchesPattern(matcher)); + + assertThat(",", not(matchesPattern(matcher))); + assertThat("x,x,x,", not(matchesPattern(matcher))); + } + + @Test + public void matchesAListWithSpecificSeparator() { + PatternMatcher matcher = new PatternMatcher(listOf("x").separatedBy(":")); + + assertThat("", matchesPattern(matcher)); + assertThat("x", matchesPattern(matcher)); + assertThat("x:x", matchesPattern(matcher)); + assertThat("x:x:x:x:x", matchesPattern(matcher)); + + assertThat("x,x,x", not(matchesPattern(matcher))); + } + + @Test + public void matchesWhitespace() { + PatternMatcher matcher = new PatternMatcher(sequence("a", whitespace(), "z")); + + assertThat("az", matchesPattern(matcher)); + assertThat("a z", matchesPattern(matcher)); + assertThat("a \t z", matchesPattern(matcher)); + } + + @Test + public void matchesSequenceSeparatedByPattern() { + PatternMatcher matcher = new PatternMatcher( + separatedBy(",", "a", "b", "c")); + + assertThat("a,b,c", matchesPattern(matcher)); + } + + @Test + public void canControlCaseSensitivity() { + PatternMatcher matcher = new PatternMatcher( + sequence("a",caseInsensitive(sequence("b",caseSensitive("c")))) + ); + + assertThat("abc", matchesPattern(matcher)); + assertThat("aBc", matchesPattern(matcher)); + assertThat("aBC", not(matchesPattern(matcher))); + } +} +```