[r5987]: incubator / regex / regex.testGroup  Maximize  Restore  History

Download this file

2177 lines (1769 with data), 85.2 kB

#!/usr/bin/rexx
/*
  SVN Revision: $Rev: 3371 $
  Change Date:  $Date: 2008-09-21 00:33:29 -0400 (Sun, 21 Sep 2008) $
*/
/*----------------------------------------------------------------------------*/
/*                                                                            */
/* Copyright (c) 2005-2010 Rexx Language Association. All rights reserved.    */
/*                                                                            */
/* This program and the accompanying materials are made available under       */
/* the terms of the Common Public License v1.0 which accompanies this         */
/* distribution. A copy is also available at the following address:           */
/* http://www.oorexx.org/license.html                                         */
/*                                                                            */
/* Redistribution and use in source and binary forms, with or                 */
/* without modification, are permitted provided that the following            */
/* conditions are met:                                                        */
/*                                                                            */
/* Redistributions of source code must retain the above copyright             */
/* notice, this list of conditions and the following disclaimer.              */
/* Redistributions in binary form must reproduce the above copyright          */
/* notice, this list of conditions and the following disclaimer in            */
/* the documentation and/or other materials provided with the distribution.   */
/*                                                                            */
/* Neither the name of Rexx Language Association nor the names                */
/* of its contributors may be used to endorse or promote products             */
/* derived from this software without specific prior written permission.      */
/*                                                                            */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS        */
/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT          */
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS          */
/* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT   */
/* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,      */
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED   */
/* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,        */
/* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY     */
/* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING    */
/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS         */
/* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.               */
/*                                                                            */
/*----------------------------------------------------------------------------*/
  parse source . . fileSpec;

  group = .TestGroup~new(fileSpec)
  group~add(.regex.testGroup)
  group~add(.regex.mutable.testGroup)

  if group~isAutomatedTest then return group

  testResult = group~suite~execute~~print

return testResult
-- End of entry point.

::requires "ooTest.frm"     -- load the ooRexxUnit classes
::requires "regex.cls"
::class "regex.mutable.testGroup" subclass "regex.testGroup" public
-- method used for test polymorphism.  Depending on the class of the
-- test group, this will either return a string or a mutablebuffer instance
-- for match, startswith, and find tests
::method td
  use arg d
  return .mutablebuffer~new(d)   -- this is the mutable buffer form

::class "regex.testGroup" subclass ooTestCase public

-- method used for test polymorphism.  Depending on the class of the
-- test group, this will either return a string or a mutablebuffer instance
-- for match, startswith, and find tests
::method td
  use arg d
  return d   -- this is the string form

-- matching methods used to handle both string and mutablebuffer variations
::method matches
  use arg pattern, string
  return pattern~matches(self~td(string))

::method startsWith
  use arg pattern, string
  return pattern~startsWith(self~td(string))

::method find
  use arg pattern, string
  return pattern~find(self~td(string))

-- utility method to perform tests on character class
-- tests to ensure they will only match characters
-- in the given set
::method checkIncludedCharacters
  use arg p, includes

  do i = 0 to 255
      -- handle the special cases
      ch = d2c(i)
      -- this is in the target set, this must match
      if includes~pos(ch) > 0 then do
          self~assertTrue(p~matches(ch), "Checking included character" ch "('"ch~c2x"'x) using pattern" p)
      end
      else do
          self~assertFalse(p~matches(ch), "Checking excluded character" ch "('"ch~c2x"'x) using pattern" p)
      end
  end

-- utility method to perform tests on character class
-- tests to ensure they will not only match characters
-- in the given set
::method checkExcludedCharacters
  use arg p, excludes

  do i = 0 to 255
      -- handle the special cases
      ch = d2c(i)
      -- this is in the target set, this must match
      if excludes~pos(ch) > 0 then do
          self~assertFalse(p~matches(ch), "Checking excluded character" ch "('"ch~c2x"'x) using pattern" p)
      end
      else do
          self~assertTrue(p~matches(ch), "Checking included character" ch "('"ch~c2x"'x) using pattern" p)
      end
  end

-- utilty method to verify a match result
::method verifyMatchResult
  use arg r, start, end, text

  res = r~matched & r~start == start & r~end == end & r~text == text & r~length == text~length
  -- if this fails, redo the comparisons with trace on to help diagnose the failure
  if \res then do
      trace i
      return r~matched & r~start == start & r~end == end & r~text == text & r~length == text~length
  end
  return .true

-- Perform a test on one of the class family sets
::method verifyClassFamily
  use arg name, characters

  p = .Pattern~compile("\p{"||name||"}")
  self~checkIncludedCharacters(p, characters)
  p = .Pattern~compile("\P{"||name||"}")
  self~checkExcludedCharacters(p, characters)
  p = .Pattern~compile("[\p{"||name||"}]")
  self~checkIncludedCharacters(p, characters)
  p = .Pattern~compile("[\P{"||name||"}]")
  self~checkExcludedCharacters(p, characters)

-- tests simple string matches
::method testAtom
  p = .Pattern~compile("foo")
  -- some basic method results from pattern
  self~assertEquals("foo", p~pattern)
  self~assertEquals("foo", p~string)

  -- now some matching/search tests
  self~assertTrue(self~matches(p, "foo"))
  self~assertFalse(self~matches(p, "foobar"))
  self~assertFalse(self~matches(p, "fo"))
  self~assertFalse(self~matches(p, " foo"))
  self~assertTrue(self~startsWith(p, "foo"))
  self~assertTrue(self~startsWith(p, "fooBar"))
  self~assertFalse(self~startsWith(p, " foo"))

  r = self~find(p, "foo")
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "foo"))
  self~assertEquals("", r~prefix)
  self~assertEquals("", r~suffix)

  r = self~find(p, "xxxfooyyy")
  self~assertTrue(self~verifyMatchResult(r, 4, 7, "foo"))
  self~assertEquals(3, r~length)
  self~assertEquals("foo", r~text)

  r = self~find(p, "xyzzy")
  self~assertFalse(r~matched)
  self~assertEquals(0, r~start)
  self~assertEquals(0, r~end)
  self~assertEquals("", r~text)
  self~assertEquals("", r~prefix)
  self~assertEquals("xyzzy", r~suffix)

  -- case insensitivity tests
  p = .Pattern~compile("foo", .RegexCompiler~new(.RegexCompiler~caseless))
  self~assertTrue(self~matches(p, "foo"))
  self~assertTrue(self~matches(p, "fOo"))
  self~assertTrue(self~matches(p, "FOO"))

  p = .Pattern~compile("foo", .RegexCompiler~new(.RegexCompiler~respectCase))
  self~assertTrue(self~matches(p, "foo"))
  self~assertFalse(self~matches(p, "fOo"))
  self~assertFalse(self~matches(p, "FOO"))

  -- flag override as a standalone group, including tests for mode restore
  p = .Pattern~compile("(?i)foo", .RegexCompiler~new(.RegexCompiler~respectCase))
  self~assertTrue(self~matches(p, "foo"))
  self~assertTrue(self~matches(p, "FOO"))

  p = .Pattern~compile("(?-i)foo", .RegexCompiler~new(.RegexCompiler~caseless))
  self~assertTrue(self~matches(p, "foo"))
  self~assertFalse(self~matches(p, "FOO"))

  -- group scope flag save and restore
  p = .Pattern~compile("((?i)foo)d", .RegexCompiler~new(.RegexCompiler~respectCase))
  self~assertTrue(self~matches(p, "food"))
  self~assertTrue(self~matches(p, "FOOd"))
  self~assertFalse(self~matches(p, "FOOD"))

  p = .Pattern~compile("((?-i)foo)d", .RegexCompiler~new(.RegexCompiler~caseless))
  self~assertTrue(self~matches(p, "fooD"))
  self~assertTrue(self~matches(p, "food"))
  self~assertFalse(self~matches(p, "FOOD"))

  -- and save and restore using the (?f:X) syntax
  p = .Pattern~compile("(?i:foo)d", .RegexCompiler~new(.RegexCompiler~respectCase))
  self~assertTrue(self~matches(p, "food"))
  self~assertTrue(self~matches(p, "FOOd"))
  self~assertFalse(self~matches(p, "FOOD"))

  p = .Pattern~compile("(?-i:foo)d", .RegexCompiler~new(.RegexCompiler~caseless))
  self~assertTrue(self~matches(p, "fooD"))
  self~assertTrue(self~matches(p, "food"))
  self~assertFalse(self~matches(p, "FOOD"))

-- test various patterns containing "."
::method testDot

  p = .Pattern~compile(".")

  -- match against all ascii characters.  However,
  -- the default match mode for "." does not recognize
  -- either '0d'x or '0a'x.  We'll invert those.  Tests
  -- for the options overrides is a task for another day.
  self~checkExcludedCharacters(p, "0a0d"x)

  self~assertFalse(self~matches(p, ""))
  self~assertFalse(self~matches(p, "AB"))

  self~assertFalse(self~startsWith(p, ""))
  self~assertTrue(self~startsWith(p, "A"))
  self~assertTrue(self~startsWith(p, "AB"))

  r = self~find(p, "foo")
  self~assertTrue(r~matched)
  self~assertEquals(1, r~start)
  self~assertEquals(2, r~end)
  self~assertEquals(1, r~length)
  self~assertEquals("f", r~text)
  self~assertEquals("", r~prefix)
  self~assertEquals("oo", r~suffix)

  -- now some composite tests
  p = .Pattern~compile("f.o")
  do i = 0 to 255
      -- handle the special cases
      if i == 10 | i == 13 then do
          self~assertFalse(self~matches(p, "f"||d2c(i)||"o"))
      end
      else do
          self~assertTrue(self~matches(p, "f"||d2c(i)||"o"))
      end
  end

  self~assertFalse(self~matches(p, "fo"))
  self~assertFalse(self~matches(p, "foobar"))

  self~assertFalse(self~startsWith(p, "fo"))
  self~assertTrue(self~startsWith(p, "foobar"))

  r = self~find(p, "foo")
  self~assertTrue(r~matched)
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "foo"))
  self~assertEquals("", r~prefix)
  self~assertEquals("", r~suffix)

  r = self~find(p, "foobar")
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "foo"))
  self~assertEquals("", r~prefix)
  self~assertEquals("bar", r~suffix)

  r = self~find(p, "xyzfoobar")
  self~assertTrue(self~verifyMatchResult(r, 4, 7, "foo"))
  self~assertEquals("xyz", r~prefix)
  self~assertEquals("bar", r~suffix)

  -- dot pattern on the end
  p = .Pattern~compile("fo.")
  do i = 0 to 255
      -- handle the special cases
      if i == 10 | i == 13 then do
          self~assertFalse(self~matches(p, "fo"||d2c(i)))
      end
      else do
          self~assertTrue(self~matches(p, "fo"||d2c(i)))
      end
  end

  self~assertFalse(self~matches(p, "fo"))
  self~assertFalse(self~matches(p, "foobar"))

  self~assertFalse(self~startsWith(p, "fo"))
  self~assertTrue(self~startsWith(p, "foo"))
  self~assertTrue(self~startsWith(p, "foobar"))

  r = self~find(p, "foo")
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "foo"))
  self~assertEquals("foo", r~text)
  self~assertEquals("", r~prefix)
  self~assertEquals("", r~suffix)

  r = self~find(p, "foobar")
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "foo"))
  self~assertEquals("", r~prefix)
  self~assertEquals("bar", r~suffix)

  r = self~find(p, "xyzfoobar")
  self~assertTrue(self~verifyMatchResult(r, 4, 7, "foo"))
  self~assertEquals("xyz", r~prefix)
  self~assertEquals("bar", r~suffix)


  -- dot pattern at the start
  p = .Pattern~compile(".oo")
  do i = 0 to 255
      -- handle the special cases
      if i == 10 | i == 13 then do
          self~assertFalse(self~matches(p, d2c(i)||"oo"))
      end
      else do
          self~assertTrue(self~matches(p, d2c(i)||"oo"))
      end
  end

  self~assertFalse(self~matches(p, "fo"))
  self~assertFalse(self~matches(p, "foobar"))

  self~assertFalse(self~startsWith(p, "fo"))
  self~assertTrue(self~startsWith(p, "foo"))
  self~assertTrue(self~startsWith(p, "foobar"))

  r = self~find(p, "foo")
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "foo"))
  self~assertEquals("", r~prefix)
  self~assertEquals("", r~suffix)

  r = self~find(p, "foobar")
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "foo"))
  self~assertEquals("", r~prefix)
  self~assertEquals("bar", r~suffix)

  r = self~find(p, "xyzfoobar")
  self~assertTrue(self~verifyMatchResult(r, 4, 7, "foo"))
  self~assertEquals("xyz", r~prefix)
  self~assertEquals("bar", r~suffix)

/*
  -- tests of various mode flags on dot behavior
  -- this is the same as the default, so it should not
  -- recognize the linends
  p = .Pattern~compile(".", .RegexCompiler~new(.RegexCompiler~dotRestricted))
  self~checkExcludedCharacters(p, "0a0d"x)
  -- now dot all mode, which will recognize everything
  p = .Pattern~compile(".", .RegexCompiler~new(.RegexCompiler~dotAll))
  self~checkExcludedCharacters(p, "")
  -- this again is the default
  p = .Pattern~compile(".", .RegexCompiler~new(.RegexCompiler~internetLines))
  self~checkExcludedCharacters(p, "0a0d"x)
  -- unix line mode only recognizes linends as special
  p = .Pattern~compile(".", .RegexCompiler~new(.RegexCompiler~unixLines))
  self~checkExcludedCharacters(p, "0a"x)

  -- now via inline override flags
  p = .Pattern~compile("(?s).", .RegexCompiler~new(.RegexCompiler~dotRestricted))
  self~checkExcludedCharacters(p, "")
  -- now dot all mode, which will recognize everything
  p = .Pattern~compile("(?-s).", .RegexCompiler~new(.RegexCompiler~dotAll))
  self~checkExcludedCharacters(p, "0a0d"x)
  -- this again is the default
  p = .Pattern~compile("(?d).", .RegexCompiler~new(.RegexCompiler~internetLines))
  self~checkExcludedCharacters(p, "0a"x)
  -- unix line mode only recognizes linends as special
  p = .Pattern~compile("(?-d).", .RegexCompiler~new(.RegexCompiler~unixLines))
  self~checkExcludedCharacters(p, "0a0d"x)
 */

-- simple classes that are just sequences of characters
::method testSimpleClass
  p = .Pattern~compile("[abc]")

  -- verify the entire included set
  self~checkIncludedCharacters(p, "abc")

  self~assertTrue(self~startsWith(p, 'abc'))
  self~assertTrue(self~startsWith(p, 'bye-bye'))
  self~assertTrue(self~startsWith(p, 'caldera'))
  self~assertFalse(self~startsWith(p, 'estuary'))

  r = self~find(p, 'abc')
  self~assertTrue(self~verifyMatchResult(r, 1, 2, "a"))
  self~assertEquals("", r~prefix)
  self~assertEquals("bc", r~suffix)

  r = self~find(p, 'xbc')
  self~assertTrue(self~verifyMatchResult(r, 2, 3, "b"))
  self~assertEquals("x", r~prefix)
  self~assertEquals("c", r~suffix)

  r = self~find(p, 'xxc')
  self~assertTrue(self~verifyMatchResult(r, 3, 4, "c"))
  self~assertEquals("xx", r~prefix)
  self~assertEquals("", r~suffix)

  p = .Pattern~compile("a[abc]c")

  r = self~find(p, 'xxabcyy')

  self~assertTrue(self~verifyMatchResult(r, 3, 6, "abc"))
  self~assertEquals("xx", r~prefix)
  self~assertEquals("yy", r~suffix)

  -- case insensitivity tests
  p = .Pattern~compile("[abc]", .RegexCompiler~new(.RegexCompiler~caseless))
  self~assertTrue(self~matches(p, "a"))
  self~assertTrue(self~matches(p, "A"))

  p = .Pattern~compile("[abc]", .RegexCompiler~new(.RegexCompiler~respectcase))
  self~assertTrue(self~matches(p, "a"))
  self~assertFalse(self~matches(p, "A"))

  p = .Pattern~compile("(?i)[abc]", .RegexCompiler~new(.RegexCompiler~respectcase))
  self~assertTrue(self~matches(p, "a"))
  self~assertTrue(self~matches(p, "A"))

  p = .Pattern~compile("(?-i)[abc]", .RegexCompiler~new(.RegexCompiler~caseless))
  self~assertTrue(self~matches(p, "a"))
  self~assertFalse(self~matches(p, "A"))

-- simple classes that are just sequences of characters, with negation
::method testSimpleNotClass
  p = .Pattern~compile("[^abc]")

  -- verify the entire excluded set
  self~checkExcludedCharacters(p, "abc")

  self~assertFalse(self~startsWith(p, 'abc'))
  self~assertFalse(self~startsWith(p, 'bye-bye'))
  self~assertFalse(self~startsWith(p, 'caldera'))
  self~assertTrue(self~startsWith(p, 'estuary'))

  r = self~find(p, 'eabc')
  self~assertTrue(self~verifyMatchResult(r, 1, 2, "e"))
  self~assertEquals("", r~prefix)
  self~assertEquals("abc", r~suffix)

  r = self~find(p, 'aebc')
  self~assertTrue(self~verifyMatchResult(r, 2, 3, "e"))
  self~assertEquals("a", r~prefix)
  self~assertEquals("bc", r~suffix)

  r = self~find(p, 'abce')
  self~assertTrue(self~verifyMatchResult(r, 4, 5, "e"))
  self~assertEquals("abc", r~prefix)
  self~assertEquals("", r~suffix)

  p = .Pattern~compile("a[^abc]c")

  r = self~find(p, 'abcaecyy')
  self~assertTrue(self~verifyMatchResult(r, 4, 7, "aec"))
  self~assertEquals("abc", r~prefix)
  self~assertEquals("yy", r~suffix)

  -- case insensitivity tests
  p = .Pattern~compile("[^abc]", .RegexCompiler~new(.RegexCompiler~caseless))
  self~assertFalse(self~matches(p, "a"))
  self~assertFalse(self~matches(p, "A"))

  p = .Pattern~compile("[^abc]", .RegexCompiler~new(.RegexCompiler~respectcase))
  self~assertFalse(self~matches(p, "a"))
  self~assertTrue(self~matches(p, "A"))

  p = .Pattern~compile("(?i)[^abc]", .RegexCompiler~new(.RegexCompiler~respectcase))
  self~assertFalse(self~matches(p, "a"))
  self~assertFalse(self~matches(p, "A"))

  p = .Pattern~compile("(?-i)[^abc]", .RegexCompiler~new(.RegexCompiler~caseless))
  self~assertFalse(self~matches(p, "a"))
  self~assertTrue(self~matches(p, "A"))


-- simple classes that are just sequences of characters, with negation
::method testRangeNotClass
  p = .Pattern~compile("[^a-c]")

  -- verify the entire excluded set
  self~checkExcludedCharacters(p, "abc")

  self~assertFalse(self~startsWith(p, 'abc'))
  self~assertFalse(self~startsWith(p, 'bye-bye'))
  self~assertFalse(self~startsWith(p, 'caldera'))
  self~assertTrue(self~startsWith(p, 'estuary'))

  r = self~find(p, 'eabc')
  self~assertTrue(self~verifyMatchResult(r, 1, 2, "e"))
  self~assertEquals("", r~prefix)
  self~assertEquals("abc", r~suffix)

  r = self~find(p, 'aebc')
  self~assertTrue(self~verifyMatchResult(r, 2, 3, "e"))
  self~assertEquals("a", r~prefix)
  self~assertEquals("bc", r~suffix)

  r = self~find(p, 'abce')
  self~assertTrue(self~verifyMatchResult(r, 4, 5, "e"))
  self~assertEquals("abc", r~prefix)
  self~assertEquals("", r~suffix)

  p = .Pattern~compile("a[^a-c]c")

  r = self~find(p, 'abcaecyy')
  self~assertTrue(self~verifyMatchResult(r, 4, 7, "aec"))
  self~assertEquals("abc", r~prefix)
  self~assertEquals("yy", r~suffix)

-- simple classes that use a range of characters
::method testRangeClass
  p = .Pattern~compile("[a-c]")

  -- verify the entire included set
  self~checkIncludedCharacters(p, "abc")

  self~assertTrue(self~startsWith(p, 'abc'))
  self~assertTrue(self~startsWith(p, 'bye-bye'))
  self~assertTrue(self~startsWith(p, 'caldera'))
  self~assertFalse(self~startsWith(p, 'estuary'))

  r = self~find(p, 'abc')
  self~assertTrue(self~verifyMatchResult(r, 1, 2, "a"))
  self~assertEquals("", r~prefix)
  self~assertEquals("bc", r~suffix)

  r = self~find(p, 'xbc')
  self~assertTrue(self~verifyMatchResult(r, 2, 3, "b"))
  self~assertEquals("x", r~prefix)
  self~assertEquals("c", r~suffix)

  r = self~find(p, 'xxc')
  self~assertTrue(self~verifyMatchResult(r, 3, 4, "c"))
  self~assertEquals("xx", r~prefix)
  self~assertEquals("", r~suffix)

  p = .Pattern~compile("a[a-c]c")

  r = self~find(p, 'xxabcyy')
  self~assertTrue(self~verifyMatchResult(r, 3, 6, "abc"))
  self~assertEquals("xx", r~prefix)
  self~assertEquals("yy", r~suffix)

-- simple classes that use multiple ranges of
::method testMultipleRangeClass
  p = .Pattern~compile("[a-bA-B]")

  -- verify the entire included set
  self~checkIncludedCharacters(p, "abAB")

  self~assertTrue(self~startsWith(p, 'abc'))
  self~assertTrue(self~startsWith(p, 'bye-bye'))
  self~assertTrue(self~startsWith(p, 'Abc'))
  self~assertTrue(self~startsWith(p, 'Bye-bye'))
  self~assertFalse(self~startsWith(p, 'estuary'))

  r = self~find(p, 'abc')
  self~assertTrue(self~verifyMatchResult(r, 1, 2, "a"))
  self~assertEquals("", r~prefix)
  self~assertEquals("bc", r~suffix)

  r = self~find(p, 'ABC')
  self~assertTrue(self~verifyMatchResult(r, 1, 2, "A"))
  self~assertEquals("", r~prefix)
  self~assertEquals("BC", r~suffix)

  r = self~find(p, 'xb')
  self~assertTrue(self~verifyMatchResult(r, 2, 3, "b"))
  self~assertEquals("x", r~prefix)
  self~assertEquals("", r~suffix)

  r = self~find(p, 'xB')
  self~assertTrue(self~verifyMatchResult(r, 2, 3, "B"))
  self~assertEquals("x", r~prefix)
  self~assertEquals("", r~suffix)

  r = self~find(p, 'xxb')
  self~assertTrue(self~verifyMatchResult(r, 3, 4, "b"))
  self~assertEquals("xx", r~prefix)
  self~assertEquals("", r~suffix)

  p = .Pattern~compile("a[a-bC-D]c")

  r = self~find(p, 'aBcabcyy')
  self~assertTrue(self~verifyMatchResult(r, 4, 7, "abc"))
  self~assertEquals("aBc", r~prefix)
  self~assertEquals("yy", r~suffix)

-- character class union tests
::method testClassUnion
  p = .Pattern~compile("[a-b[A-B]]")

  -- verify the entire included set
  self~checkIncludedCharacters(p, "abAB")

  self~assertTrue(self~startsWith(p, 'abc'))
  self~assertTrue(self~startsWith(p, 'bye-bye'))
  self~assertTrue(self~startsWith(p, 'Abc'))
  self~assertTrue(self~startsWith(p, 'Bye-bye'))
  self~assertFalse(self~startsWith(p, 'estuary'))

  r = self~find(p, 'abc')
  self~assertTrue(self~verifyMatchResult(r, 1, 2, "a"))
  self~assertEquals("", r~prefix)
  self~assertEquals("bc", r~suffix)

  r = self~find(p, 'ABC')
  self~assertTrue(self~verifyMatchResult(r, 1, 2, "A"))
  self~assertEquals("", r~prefix)
  self~assertEquals("BC", r~suffix)

  r = self~find(p, 'xb')
  self~assertTrue(self~verifyMatchResult(r, 2, 3, "b"))
  self~assertEquals("x", r~prefix)
  self~assertEquals("", r~suffix)

  r = self~find(p, 'xB')
  self~assertTrue(self~verifyMatchResult(r, 2, 3, "B"))
  self~assertEquals("x", r~prefix)
  self~assertEquals("", r~suffix)

  r = self~find(p, 'xxb')
  self~assertTrue(self~verifyMatchResult(r, 3, 4, "b"))
  self~assertEquals("xx", r~prefix)
  self~assertEquals("", r~suffix)

  p = .Pattern~compile("a[a-b[C-D]]c")

  r = self~find(p, 'aBcabcyy')
  self~assertTrue(self~verifyMatchResult(r, 4, 7, "abc"))
  self~assertEquals("aBc", r~prefix)
  self~assertEquals("yy", r~suffix)

-- character class intersection tests
::method testClassIntersection
  p = .Pattern~compile("[a-z&&[abc]]")

  -- verify the entire included set
  self~checkIncludedCharacters(p, "abc")

  self~assertTrue(self~startsWith(p, 'abc'))
  self~assertTrue(self~startsWith(p, 'bye-bye'))
  self~assertTrue(self~startsWith(p, 'causeway'))
  self~assertFalse(self~startsWith(p, 'estuary'))

  r = self~find(p, 'abc')
  self~assertTrue(self~verifyMatchResult(r, 1, 2, "a"))

  r = self~find(p, 'ABC')
  self~assertFalse(r~matched)

  r = self~find(p, 'xb')
  self~assertTrue(self~verifyMatchResult(r, 2, 3, "b"))

  -- some subraction.  This is essentially the same pattern
  -- as the first one, but the intersection is done by exclusion
  p = .Pattern~compile("[a-z&&[^d-z]]")

  -- verify the entire included set
  self~checkIncludedCharacters(p, "abc")

  self~assertTrue(self~startsWith(p, 'abc'))
  self~assertTrue(self~startsWith(p, 'bye-bye'))
  self~assertTrue(self~startsWith(p, 'causeway'))
  self~assertFalse(self~startsWith(p, 'estuary'))

  r = self~find(p, 'abc')
  self~assertTrue(self~verifyMatchResult(r, 1, 2, "a"))

  r = self~find(p, 'ABC')
  self~assertFalse(r~matched)

  r = self~find(p, 'xb')
  self~assertTrue(self~verifyMatchResult(r, 2, 3, "b"))

-- predefined character classes
::method testPredefinedClasses
-- NOTE:  We're only going to test the matches
-- here.  By this point, all of the different
-- matches/startsWith/find options have been sufficiently
-- tested that if one works, they should all work correctly.

  -- all digits
  p = .Pattern~compile("\d")
  self~checkIncludedCharacters(p, "0123456789")

  -- as part of a class specification
  p = .Pattern~compile("[a\db]")
  self~checkIncludedCharacters(p, "ab0123456789")

  -- no digits
  p = .Pattern~compile("\D")
  self~checkExcludedCharacters(p, "0123456789")

  -- no digits but 1 and 2 added back in
  p = .Pattern~compile("[\D12]")
  self~checkExcludedCharacters(p, "03456789")

  -- whitespace
  p = .Pattern~compile("\s")
  self~checkIncludedCharacters(p, "20090a0b0c0d"x)

  -- whitespace + a couple
  p = .Pattern~compile("[a\sb]")
  self~checkIncludedCharacters(p, "ab"||"20090a0b0c0d"x)

  -- non-whitespace
  p = .Pattern~compile("\S")
  self~checkExcludedCharacters(p, "20090a0b0c0d"x)

  -- non-whitespace + a couple while space
  p = .Pattern~compile("[ \S\t]" )
  self~checkExcludedCharacters(p, "0a0b0c0d"x)

  -- word character
  p = .Pattern~compile("\w")
  self~checkIncludedCharacters(p, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789")

  -- word character plus a couple
  p = .Pattern~compile("[ \w\t]")
  self~checkIncludedCharacters(p, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789 " || "09"x)

  -- non-word character
  p = .Pattern~compile("\W")
  self~checkExcludedCharacters(p, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789")

  -- non-word character, plus some added back in
  p = .Pattern~compile("[a\Wb]")
  self~checkExcludedCharacters(p, "cdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789")


-- tests of the * pattern modifier
::method testStarModifier
  p = .Pattern~compile("a*")     -- zero or more occurrances of a
  self~assertTrue(self~matches(p, ""))  -- null string should match
  self~assertTrue(self~matches(p, "a")) -- single a should match
  self~assertTrue(self~matches(p, "aaaaaa")) -- multiple a's should match
  self~assertFalse(self~matches(p, "aaaaaaq")) -- the trailing one should not

  -- a few starts tests.  These are all true
  self~assertTrue(self~startsWith(p, ""))  -- null string should match
  self~assertTrue(self~startsWith(p, "a")) -- single a should match
  self~assertTrue(self~startsWith(p, "aaaaaa")) -- multiple a's should match
  self~assertTrue(self~startsWith(p, "aaaaaaq")) -- This should also match

  r = self~find(p, "xyzaxyz")
  -- because this matches no characters, this will be a zero length match
  -- at the beginning
  self~assertTrue(self~verifyMatchResult(r, 1, 1, ""))

  r = self~find(p, "aaaaxyz")
  -- because this matches all of the a characters at the beginning
  -- at the beginning
  self~assertTrue(self~verifyMatchResult(r, 1, 5, "aaaa"))

  p = .Pattern~compile("ab*c")     -- repetive in the middle
  self~assertTrue(self~matches(p, "ac"))  -- no b's are fine
  self~assertTrue(self~matches(p, "abc"))  -- one should be ok too
  self~assertTrue(self~matches(p, "abbbbbbbbbbbbbbbbbc"))  -- and a whole bunch

  -- example from the online tutorial

  p = .Pattern~compile(".*foo")     -- this is a greedy pattern
  self~assertTrue(self~matches(p, "xfooxxxxxxfoo"))  -- should consume the entire string
  self~assertTrue(self~startsWith(p, "xfooxxxxxxfoo"))  -- one should be ok too
  -- this should match the entire string
  r = self~find(p, "xfooxxxxxxfoo")
  self~assertTrue(self~verifyMatchResult(r, 1, 14, "xfooxxxxxxfoo"))

  -- example from the online tutorial

  p = .Pattern~compile(".*?foo")     -- this is a reluctant pattern
  self~assertTrue(self~matches(p, "xfooxxxxxxfoo"))  -- should consume the entire string
  self~assertTrue(self~startsWith(p, "xfooxxxxxxfoo"))  -- one should be ok too, but it really only matches the beginning

  self~assertFalse(self~matches(p, "xfooxxxxxxfo"))  -- should NOT work because it will not match everything
  self~assertTrue(self~startsWith(p, "xfooxxxxxxfo"))  -- this is really the same as the first one

  r = self~find(p, "xfooxxxxxxfoo")

  -- this will stop at the first match rather than
  -- consuming everything.
  self~assertTrue(self~verifyMatchResult(r, 1, 5, "xfoo"))

  -- example from the online tutorial

  p = .Pattern~compile(".*+foo")     -- this is a possessive pattern
  -- should not match because the .*? part will consume the entire
  -- string
  self~assertFalse(self~matches(p, "xfooxxxxxxfoo"))
  self~assertFalse(self~startsWith(p, "xfooxxxxxxfoo"))  -- same reason
  self~assertFalse(self~startsWith(p, "xfooxxxxxxfo"))  -- this is really the same as the first one

  -- this not be found
  r = self~find(p, "xfooxxxxxxfoo")
  self~assertFalse(r~matched)

-- tests of the + pattern modifier
::method testPlusModifier
  p = .Pattern~compile("a+")     -- zero or more occurrances of a
  self~assertFalse(self~matches(p, ""))  -- null string should not match
  self~assertTrue(self~matches(p, "a")) -- single a should match
  self~assertTrue(self~matches(p, "aaaaaa")) -- multiple a's should match
  self~assertFalse(self~matches(p, "aaaaaaq")) -- the trailing one should not

  -- a few starts tests.  These are all true
  self~assertFalse(self~startsWith(p, ""))  -- null string not should match
  self~assertTrue(self~startsWith(p, "a")) -- single a should match
  self~assertTrue(self~startsWith(p, "aaaaaa")) -- multiple a's should match
  self~assertTrue(self~startsWith(p, "aaaaaaq")) -- should also match

  r = self~find(p, "xyzaxyz")
  -- because this must match at least one character, it will locate the a
  -- in the middle
  self~assertTrue(self~verifyMatchResult(r, 4, 5, "a"))

  r = self~find(p, "aaaaxyz")
  -- because this matches all of the a characters at the beginning
  -- at the beginning
  self~assertTrue(self~verifyMatchResult(r, 1, 5, "aaaa"))

  p = .Pattern~compile("ab+c")     -- repetitive in the middle
  self~assertFalse(self~matches(p, "ac"))  -- must have at least one b
  self~assertTrue(self~matches(p, "abc"))  -- one should be ok too
  self~assertTrue(self~matches(p, "abbbbbbbbbbbbbbbbbc"))  -- and a whole bunch

-- tests of the ? pattern modifier
::method testQuestionModifier
  p = .Pattern~compile("a?")     -- zero or more occurrances of a
  self~assertTrue(self~matches(p, ""))  -- null string should match
  self~assertTrue(self~matches(p, "a")) -- single a should match
  self~assertFalse(self~matches(p, "aa")) -- multiple a's should not

  -- a few startsWith tests.  These are all true
  self~assertTrue(self~startsWith(p, ""))  -- null string should match
  self~assertTrue(self~startsWith(p, "a")) -- single a should match
  self~assertTrue(self~startsWith(p, "aa")) -- multiple a's should match

  r = self~find(p, "xyzaxyz")
  -- because this can match "nothing", this will be a zero length match at the beginning
  self~assertTrue(self~verifyMatchResult(r, 1, 1, ""))

  r = self~find(p, "aaaaxyz")
  -- because this will only match the first a at the beginning
  self~assertTrue(self~verifyMatchResult(r, 1, 2, "a"))

  p = .Pattern~compile("ab?c")     -- repetitive in the middle
  self~assertTrue(self~matches(p, "ac"))  -- need not have a b
  self~assertTrue(self~matches(p, "abc"))  -- one should be ok too
  self~assertFalse(self~matches(p, "abbbbbbbbbbbbbbbbbc"))  -- only zero or 1 b works

-- tests of the {n} pattern modifier
::method testGreedyExactCountModifier
  p = .Pattern~compile("a{3}")     -- exactly 3 occurrances of a
  self~assertFalse(self~matches(p, ""))  -- null string should not match
  self~assertFalse(self~matches(p, "a")) -- single a should not match
  self~assertFalse(self~matches(p, "aa")) -- one less than the required
  self~assertTrue(self~matches(p, "aaa")) -- The required number
  self~assertFalse(self~matches(p, "aaaa")) -- One required number

  -- a few startsWith tests.
  self~assertFalse(self~startsWith(p, ""))  -- null string should not match
  self~assertFalse(self~startsWith(p, "aa")) -- still not enough
  self~assertTrue(self~startsWith(p, "aaa")) -- this is ok
  self~assertTrue(self~startsWith(p, "aaaa")) -- as is this

  r = self~find(p, "xaaxaaaxyz")
  -- this will only match at the second grouping of a's
  self~assertTrue(r~matched)
  self~assertEquals(5, r~start)
  self~assertEquals(8, r~end)
  self~assertEquals("aaa", r~text)

  p = .Pattern~compile("ab{2}c")     -- repetitive in the middle
  self~assertFalse(self~matches(p, "ac"))  -- must have 2 a's
  self~assertFalse(self~matches(p, "abc"))  -- also bad
  self~assertTrue(self~matches(p, "abbc"))  -- this is good
  self~assertFalse(self~matches(p, "abbbc"))  -- overshot the mark

-- tests of the {n}? pattern modifier
::method testReluctantExactCountModifier
  -- Since this only matches an exact number of times, these are
  -- really identical to greedy.  It either matches or it doesn't.

  p = .Pattern~compile("a{3}?")     -- exactly 3 occurrances of a
  self~assertFalse(self~matches(p, ""))  -- null string should not match
  self~assertFalse(self~matches(p, "a")) -- single a should not match
  self~assertFalse(self~matches(p, "aa")) -- one less than the required
  self~assertTrue(self~matches(p, "aaa")) -- The required number
  self~assertFalse(self~matches(p, "aaaa")) -- One required number

  -- a few startsWith tests.
  self~assertFalse(self~startsWith(p, ""))  -- null string should not match
  self~assertFalse(self~startsWith(p, "aa")) -- still not enough
  self~assertTrue(self~startsWith(p, "aaa")) -- this is ok
  self~assertTrue(self~startsWith(p, "aaaa")) -- as is this

  r = self~find(p, "xaaxaaaxyz")
  -- this will only match at the second grouping of a's
  self~assertTrue(r~matched)
  self~assertEquals(5, r~start)
  self~assertEquals(8, r~end)
  self~assertEquals("aaa", r~text)

  p = .Pattern~compile("ab{2}?c")     -- repetitive in the middle
  self~assertFalse(self~matches(p, "ac"))  -- must have 2 a's
  self~assertFalse(self~matches(p, "abc"))  -- also bad
  self~assertTrue(self~matches(p, "abbc"))  -- this is good
  self~assertFalse(self~matches(p, "abbbc"))  -- overshot the mark

-- tests of the {n}+ pattern modifier
::method testPossessiveExactCountModifier
  -- Since this only matches an exact number of times, these are
  -- really identical to greedy.  It either matches or it doesn't.

  p = .Pattern~compile("a{3}+")     -- exactly 3 occurrances of a
  self~assertFalse(self~matches(p, ""))  -- null string should not match
  self~assertFalse(self~matches(p, "a")) -- single a should not match
  self~assertFalse(self~matches(p, "aa")) -- one less than the required
  self~assertTrue(self~matches(p, "aaa")) -- The required number
  self~assertFalse(self~matches(p, "aaaa")) -- One required number

  -- a few startsWith tests.
  self~assertFalse(self~startsWith(p, ""))  -- null string should not match
  self~assertFalse(self~startsWith(p, "aa")) -- still not enough
  self~assertTrue(self~startsWith(p, "aaa")) -- this is ok
  self~assertTrue(self~startsWith(p, "aaaa")) -- as is this

  r = self~find(p, "xaaxaaaxyz")
  -- this will only match at the second grouping of a's
  self~assertTrue(r~matched)
  self~assertEquals(5, r~start)
  self~assertEquals(8, r~end)
  self~assertEquals("aaa", r~text)

  p = .Pattern~compile("ab{2}+c")     -- repetitive in the middle
  self~assertFalse(self~matches(p, "ac"))  -- must have 2 a's
  self~assertFalse(self~matches(p, "abc"))  -- also bad
  self~assertTrue(self~matches(p, "abbc"))  -- this is good
  self~assertFalse(self~matches(p, "abbbc"))  -- overshot the mark

-- tests of the {n,m} pattern modifier
::method testMinMaxCountModifier
  p = .Pattern~compile("a{2,4}")     -- at least 2, no more than 4
  self~assertFalse(self~matches(p, ""))  -- null string should not match
  self~assertFalse(self~matches(p, "a")) -- single a should not match
  self~assertTrue(self~matches(p, "aa")) -- should match
  self~assertTrue(self~matches(p, "aaa")) -- ditto
  self~assertTrue(self~matches(p, "aaaa")) -- The limit
  self~assertFalse(self~matches(p, "aaaaa")) -- nope

  -- a few startsWith tests.
  self~assertFalse(self~startsWith(p, ""))  -- null string should not match
  self~assertFalse(self~startsWith(p, "a")) -- single a should not match
  self~assertTrue(self~startsWith(p, "aa")) -- should match
  self~assertTrue(self~startsWith(p, "aaa")) -- ditto
  self~assertTrue(self~startsWith(p, "aaaa")) -- The limit
  self~assertTrue(self~startsWith(p, "aaaaa")) -- the extra is ignored.
  self~assertTrue(self~startsWith(p, "aaaa")) -- as is this

  r = self~find(p, "xaxaaaxyz")
  -- this will only match at the second grouping of a's
  self~assertTrue(self~verifyMatchResult(r, 4, 7, "aaa"))

  r = self~find(p, "xaxaaaaxyz")
  -- this should match the full 4 characters
  self~assertTrue(self~verifyMatchResult(r, 4, 8, "aaaa"))

  p = .Pattern~compile("ab{2,3}c")     -- repetitive in the middle
  self~assertFalse(self~matches(p, "ac"))  -- must have 2 a's
  self~assertFalse(self~matches(p, "abc"))  -- also bad
  self~assertTrue(self~matches(p, "abbc"))  -- this is good
  self~assertTrue(self~matches(p, "abbbc"))  -- should also work
  self~assertFalse(self~matches(p, "abbbbc"))  -- should fail

  -- example from the online tutorial

  p = .Pattern~compile(".{2,4}x")     -- this is a greedy pattern
  self~assertTrue(self~matches(p, "xxxxx"))  -- should consume the entire string
  self~assertTrue(self~matches(p, "xxxx"))   -- should consume the entire string
  self~assertTrue(self~matches(p, "xxx"))   -- should consume the entire string
  self~assertTrue(self~startsWith(p, "xxxx"))  -- one should be ok too
  -- this should match the maximum number it can, plus the
  -- extra trailing x
  r = self~find(p, "xfooxxxxxxfoo")
  self~assertTrue(self~verifyMatchResult(r, 1, 6, "xfoox"))

  -- example from the online tutorial

  p = .Pattern~compile(".{2,4}?x")     -- this is a reluctant pattern
  self~assertTrue(self~matches(p, "xxx"))  -- should consume the entire string
  self~assertTrue(self~matches(p, "xxxx"))  -- should consume the entire string
  self~assertTrue(self~matches(p, "xxxxx"))  -- should consume the entire string
  self~assertTrue(self~startsWith(p, "xxxfooxxxxxxfoo"))  -- one should be ok too, but it really only matches the beginning

  self~assertFalse(self~matches(p, "xfooxxxxxxfo"))  -- should NOT work because it will not match everything
  self~assertTrue(self~startsWith(p, "xfooxxxxxxfo"))  -- this is really the same as the first one

  r = self~find(p, "xfoxxxxxxxfoo")

  -- this will stop at the first match rather than
  -- consuming everything.
  self~assertTrue(self~verifyMatchResult(r, 1, 5, "xfox"))

  -- example from the online tutorial

  p = .Pattern~compile(".*+foo")     -- this is a possessive pattern
  -- should not match because the .*? part will consume the entire
  -- string
  self~assertFalse(self~matches(p, "xfooxxxxxxfoo"))
  self~assertFalse(self~startsWith(p, "xfooxxxxxxfoo"))  -- same reason
  self~assertFalse(self~startsWith(p, "xfooxxxxxxfo"))  -- this is really the same as the first one

  -- this not be found
  r = self~find(p, "xfooxxxxxxfoo")
  self~assertFalse(r~matched)

-- tests of the {n,} pattern modifier
::method testAtLeastCountModifier
  p = .Pattern~compile("a{3,}")     -- exactly 3 occurrances of a
  self~assertFalse(self~matches(p, ""))  -- null string should not match
  self~assertFalse(self~matches(p, "a")) -- single a should not match
  self~assertFalse(self~matches(p, "aa")) -- one less than the required
  self~assertTrue(self~matches(p, "aaa")) -- The required number
  self~assertTrue(self~matches(p, "aaaa")) -- still good

  -- a few startsWith tests.
  self~assertFalse(self~startsWith(p, ""))  -- null string should not match
  self~assertFalse(self~startsWith(p, "aa")) -- still not enough
  self~assertTrue(self~startsWith(p, "aaa")) -- this is ok
  self~assertTrue(self~startsWith(p, "aaaa")) -- as is this

  r = self~find(p, "xaaxaaaxyz")
  -- this will only match at the second grouping of a's
  self~assertTrue(self~verifyMatchResult(r, 5, 8, "aaa"))

  r = self~find(p, "xaaxaaaaxyz")
  -- this should match the full 4 characters
  self~assertTrue(self~verifyMatchResult(r, 5, 9, "aaaa"))

  p = .Pattern~compile("ab{2,}c")     -- repetitive in the middle
  self~assertFalse(self~matches(p, "ac"))  -- must have 2 a's
  self~assertFalse(self~matches(p, "abc"))  -- also bad
  self~assertTrue(self~matches(p, "abbc"))  -- this is good
  self~assertTrue(self~matches(p, "abbbc"))  -- should also work

  -- example from the online tutorial

  p = .Pattern~compile(".{2,}x")     -- this is a greedy pattern
  self~assertTrue(self~matches(p, "xxxxx"))  -- should consume the entire string
  self~assertTrue(self~matches(p, "xxx"))   -- should consume the entire string
  self~assertFalse(self~matches(p, "xx"))   -- not long enough
  self~assertTrue(self~startsWith(p, "xxxx"))  -- one should be ok too

  -- this should grab as much as it can, then back up to the first match
  -- extra trailing x
  r = self~find(p, "xfooxxxxxxfoo")
  self~assertTrue(self~verifyMatchResult(r, 1, 11, "xfooxxxxxx"))

  -- example from the online tutorial

  p = .Pattern~compile(".{2,}?x")     -- this is a reluctant pattern
  self~assertTrue(self~matches(p, "xxx"))  -- should consume the entire string
  self~assertTrue(self~matches(p, "xxxx"))  -- should consume the entire string
  self~assertTrue(self~matches(p, "xxxxx"))  -- should consume the entire string
  self~assertTrue(self~startsWith(p, "xxxfooxxxxxxfoo"))  -- one should be ok too, but it really only matches the beginning

  self~assertFalse(self~matches(p, "xfooxxxxxxfo"))  -- should NOT work because it will not match everything
  self~assertTrue(self~startsWith(p, "xfooxxxxxxfo"))  -- this is really the same as the first one

  r = self~find(p, "xfoxxxxxxxfoo")

  -- this will stop at the first match rather than
  -- consuming everything.
  self~assertTrue(self~verifyMatchResult(r, 1, 5, "xfox"))

  -- example from the online tutorial

  p = .Pattern~compile(".{2,}+foo")     -- this is a possessive pattern
  -- should  match because the .*? part will consume the entire
  -- string
  self~assertFalse(self~matches(p, "xfooxxxxxxfoo"))
  self~assertFalse(self~startsWith(p, "xfooxxxxxxfoo"))  -- same reason
  self~assertFalse(self~startsWith(p, "xfooxxxxxxfo"))  -- this is really the same as the first one

  -- this not be found
  r = self~find(p, "xfooxxxxxxfoo")
  self~assertFalse(r~matched)

-- various group tests
::method testGroup
  -- very simple group
  p = .Pattern~compile("(abc)")
  self~assertTrue(self~matches(p, "abc"))
  self~assertFalse(self~matches(p, "abcabc"))
  self~assertTrue(self~startsWith(p, "abcabc"))

  r = self~find(p, "abcabc")
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "abc"))

  g = r~group(1)   -- we should have group information available
  -- which in this case, should be the same as the main information
  self~assertTrue(self~verifyMatchResult(g, 1, 4, "abc"))
  -- group zero is supposed to be the same as the entire match.  Verify
  -- we get good information here
  self~assertTrue(self~verifyMatchResult(r~group(0), r~start, r~end, r~text))

  -- now with a repetitor
  p = .Pattern~compile("(abc)*")
  self~assertTrue(self~matches(p, "abc"))
  self~assertTrue(self~matches(p, "abcabc"))
  self~assertTrue(self~startsWith(p, "abcabc"))

  -- this should match everything
  r = self~find(p, "abcabc")
  self~assertTrue(self~verifyMatchResult(r, 1, 7, "abcabc"))

  -- test with multiple groups
  p = .Pattern~compile("((a)(b(c)))")
  r = self~find(p, "abcabc")
  -- this should match "abc"
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "abc"))
  -- now verify each of the groups 0-4

  -- group zero is always the main match
  self~assertTrue(self~verifyMatchResult(r~group(0), 1, 4, "abc"))
  -- ((a)(b(c))))
  self~assertTrue(self~verifyMatchResult(r~group(1), 1, 4, "abc"))
  -- (a)
  self~assertTrue(self~verifyMatchResult(r~group(2), 1, 2, "a"))
  -- (b(c))
  self~assertTrue(self~verifyMatchResult(r~group(3), 2, 4, "bc"))
  -- (c)
  self~assertTrue(self~verifyMatchResult(r~group(4), 3, 4, "c"))

  -- a back match
  p = .Pattern~compile("(\d\d)\1")
  self~assertTrue(self~matches(p, "1212"))
  self~assertFalse(self~matches(p, "12"))
  self~assertFalse(self~matches(p, "1234"))


  -- another back match test.  This matches the
  -- last repetition of the repeated group
  p = .Pattern~compile("(\d\d){2}\1")
  self~assertTrue(self~matches(p, "123434"))
  self~assertFalse(self~matches(p, "123412"))

  -- case insensitivity tests
  p = .Pattern~compile("(ab)\1", .RegexCompiler~new(.RegexCompiler~caseless))
  self~assertTrue(self~matches(p, "abab"))
  self~assertTrue(self~matches(p, "abAB"))

  p = .Pattern~compile("(ab)\1", .RegexCompiler~new(.RegexCompiler~respectcase))
  self~assertTrue(self~matches(p, "abab"))
  self~assertFalse(self~matches(p, "abAB"))

  p = .Pattern~compile("(ab)(?i)\1", .RegexCompiler~new(.RegexCompiler~respectcase))
  self~assertTrue(self~matches(p, "abab"))
  self~assertTrue(self~matches(p, "abAB"))

  p = .Pattern~compile("(ab)(?-i)\1", .RegexCompiler~new(.RegexCompiler~caseless))
  self~assertTrue(self~matches(p, "abab"))
  self~assertFalse(self~matches(p, "abAB"))

  p = .Pattern~compile("(ab)(?i:\1)", .RegexCompiler~new(.RegexCompiler~respectcase))
  self~assertTrue(self~matches(p, "abab"))
  self~assertTrue(self~matches(p, "abAB"))

  p = .Pattern~compile("(ab)(?-i:\1)", .RegexCompiler~new(.RegexCompiler~caseless))
  self~assertTrue(self~matches(p, "abab"))
  self~assertFalse(self~matches(p, "abAB"))

-- tests of the * pattern modifier
::method testStarGroupModifier
  p = .Pattern~compile("(a)*")     -- zero or more occurrances of a
  self~assertTrue(self~matches(p, ""))  -- null string should match
  self~assertTrue(self~matches(p, "a")) -- single a should match
  self~assertTrue(self~matches(p, "aaaaaa")) -- multiple a's should match
  self~assertFalse(self~matches(p, "aaaaaaq")) -- the trailing one should not

  -- a few starts tests.  These are all true
  self~assertTrue(self~startsWith(p, ""))  -- null string should match
  self~assertTrue(self~startsWith(p, "a")) -- single a should match
  self~assertTrue(self~startsWith(p, "aaaaaa")) -- multiple a's should match
  self~assertTrue(self~startsWith(p, "aaaaaaq")) -- This should also match

  r = self~find(p, "xyzaxyz")
  -- because this matches no characters, this will be a zero length match
  -- at the beginning
  self~assertTrue(self~verifyMatchResult(r, 1, 1, ""))

  r = self~find(p, "aaaaxyz")
  -- because this matches all of the a characters at the beginning
  -- at the beginning
  self~assertTrue(self~verifyMatchResult(r, 1, 5, "aaaa"))

  p = .Pattern~compile("a(b)*c")     -- repetive in the middle
  self~assertTrue(self~matches(p, "ac"))  -- no b's are fine
  self~assertTrue(self~matches(p, "abc"))  -- one should be ok too
  self~assertTrue(self~matches(p, "abbbbbbbbbbbbbbbbbc"))  -- and a whole bunch

  -- example from the online tutorial

  p = .Pattern~compile("(.)*foo")     -- this is a greedy pattern
  self~assertTrue(self~matches(p, "xfooxxxxxxfoo"))  -- should consume the entire string
  self~assertTrue(self~startsWith(p, "xfooxxxxxxfoo"))  -- one should be ok too
  -- this should match the entire string
  r = self~find(p, "xfooxxxxxxfoo")

  self~assertTrue(self~verifyMatchResult(r, 1, 14, "xfooxxxxxxfoo"))

  -- example from the online tutorial

  p = .Pattern~compile("(.)*?foo")     -- this is a reluctant pattern
  self~assertTrue(self~matches(p, "xfooxxxxxxfoo"))  -- should consume the entire string
  self~assertTrue(self~startsWith(p, "xfooxxxxxxfoo"))  -- one should be ok too, but it really only matches the beginning

  self~assertFalse(self~matches(p, "xfooxxxxxxfo"))  -- should NOT work because it will not match everything
  self~assertTrue(self~startsWith(p, "xfooxxxxxxfo"))  -- this is really the same as the first one

  r = self~find(p, "xfooxxxxxxfoo")

  -- this will stop at the first match rather than
  -- consuming everything.
  self~assertTrue(self~verifyMatchResult(r, 1, 5, "xfoo"))

  -- example from the online tutorial

  p = .Pattern~compile("(.)*+foo")     -- this is a possessive pattern
  -- should not match because the .*? part will consume the entire
  -- string
  self~assertFalse(self~matches(p, "xfooxxxxxxfoo"))
  self~assertFalse(self~startsWith(p, "xfooxxxxxxfoo"))  -- same reason
  self~assertFalse(self~startsWith(p, "xfooxxxxxxfo"))  -- this is really the same as the first one

  -- this not be found
  r = self~find(p, "xfooxxxxxxfoo")
  self~assertFalse(r~matched)


-- tests of the + pattern modifier
::method testPlusGroupModifier
  p = .Pattern~compile("(a)+")     -- zero or more occurrances of a
  self~assertFalse(self~matches(p, ""))  -- null string should not match
  self~assertTrue(self~matches(p, "a")) -- single a should match
  self~assertTrue(self~matches(p, "aaaaaa")) -- multiple a's should match
  self~assertFalse(self~matches(p, "aaaaaaq")) -- the trailing one should not

  -- a few starts tests.  These are all true
  self~assertFalse(self~startsWith(p, ""))  -- null string not should match
  self~assertTrue(self~startsWith(p, "a")) -- single a should match
  self~assertTrue(self~startsWith(p, "aaaaaa")) -- multiple a's should match
  self~assertTrue(self~startsWith(p, "aaaaaaq")) -- should also match

  r = self~find(p, "xyzaxyz")
  -- because this must match at least one character, it will locate the a
  -- in the middle
  self~assertTrue(self~verifyMatchResult(r, 4, 5, "a"))
  self~assertTrue(self~verifyMatchResult(r~group(1), 4, 5, "a"))

  r = self~find(p, "aaaaxyz")
  -- because this matches all of the a characters at the beginning
  -- at the beginning
  self~assertTrue(self~verifyMatchResult(r, 1, 5, "aaaa"))
  self~assertTrue(self~verifyMatchResult(r~group(1), 4, 5, "a"))

  p = .Pattern~compile("a(b)+c")     -- repetitive in the middle
  self~assertFalse(self~matches(p, "ac"))  -- must have at least one b
  self~assertTrue(self~matches(p, "abc"))  -- one should be ok too
  self~assertTrue(self~matches(p, "abbbbbbbbbbbbbbbbbc"))  -- and a whole bunch

-- tests of the ? pattern modifier
::method testQuestionGroupModifier
  p = .Pattern~compile("(a)?")     -- zero or more occurrances of a
  self~assertTrue(self~matches(p, ""))  -- null string should match
  self~assertTrue(self~matches(p, "a")) -- single a should match
  self~assertFalse(self~matches(p, "aa")) -- multiple a's should not

  -- a few startsWith tests.  These are all true
  self~assertTrue(self~startsWith(p, ""))  -- null string should match
  self~assertTrue(self~startsWith(p, "a")) -- single a should match
  self~assertTrue(self~startsWith(p, "aa")) -- multiple a's should match

  r = self~find(p, "xyzaxyz")
  -- because this can match "nothing", this will be a zero length match at the beginning
  self~assertTrue(self~verifyMatchResult(r, 1, 1, ""))
  self~assertTrue(self~verifyMatchResult(r~group(1), 1, 1, ""))

  r = self~find(p, "aaaaxyz")
  -- because this will only match the first a at the beginning
  self~assertTrue(self~verifyMatchResult(r, 1, 2, "a"))
  self~assertTrue(self~verifyMatchResult(r~group(1), 1, 2, "a"))

  p = .Pattern~compile("a(b)?c")     -- repetitive in the middle
  self~assertTrue(self~matches(p, "ac"))  -- need not have a b
  self~assertTrue(self~matches(p, "abc"))  -- one should be ok too
  self~assertFalse(self~matches(p, "abbbbbbbbbbbbbbbbbc"))  -- only zero or 1 b works

-- tests of the {n} pattern modifier
::method testExactCountGroupModifier
  p = .Pattern~compile("(a){3}")     -- exactly 3 occurrances of a
  self~assertFalse(self~matches(p, ""))  -- null string should not match
  self~assertFalse(self~matches(p, "a")) -- single a should not match
  self~assertFalse(self~matches(p, "aa")) -- one less than the required
  self~assertTrue(self~matches(p, "aaa")) -- The required number
  self~assertFalse(self~matches(p, "aaaa")) -- One required number

  -- a few startsWith tests.
  self~assertFalse(self~startsWith(p, ""))  -- null string should not match
  self~assertFalse(self~startsWith(p, "aa")) -- still not enough
  self~assertTrue(self~startsWith(p, "aaa")) -- this is ok
  self~assertTrue(self~startsWith(p, "aaaa")) -- as is this

  r = self~find(p, "xaaxaaaxyz")
  -- this will only match at the second grouping of a's
  self~assertTrue(self~verifyMatchResult(r, 5, 8, "aaa"))
  self~assertTrue(self~verifyMatchResult(r~group(1), 7, 8, "a"))

  p = .Pattern~compile("a(b){2}c")     -- repetitive in the middle
  self~assertFalse(self~matches(p, "ac"))  -- must have 2 a's
  self~assertFalse(self~matches(p, "abc"))  -- also bad
  self~assertTrue(self~matches(p, "abbc"))  -- this is good
  self~assertFalse(self~matches(p, "abbbc"))  -- overshot the mark

-- tests of the {n,m} pattern modifier
::method testMinMaxCountGroupModifier
  p = .Pattern~compile("(a){2,4}")     -- at least 2, no more than 4
  self~assertFalse(self~matches(p, ""))  -- null string should not match
  self~assertFalse(self~matches(p, "a")) -- single a should not match
  self~assertTrue(self~matches(p, "aa")) -- should match
  self~assertTrue(self~matches(p, "aaa")) -- ditto
  self~assertTrue(self~matches(p, "aaaa")) -- The limit
  self~assertFalse(self~matches(p, "aaaaa")) -- nope

  -- a few startsWith tests.
  self~assertFalse(self~startsWith(p, ""))  -- null string should not match
  self~assertFalse(self~startsWith(p, "a")) -- single a should not match
  self~assertTrue(self~startsWith(p, "aa")) -- should match
  self~assertTrue(self~startsWith(p, "aaa")) -- ditto
  self~assertTrue(self~startsWith(p, "aaaa")) -- The limit
  self~assertTrue(self~startsWith(p, "aaaaa")) -- the extra is ignored.
  self~assertTrue(self~startsWith(p, "aaaa")) -- as is this

  r = self~find(p, "xaxaaaxyz")
  -- this will only match at the second grouping of a's
  self~assertTrue(self~verifyMatchResult(r, 4, 7, "aaa"))
  self~assertTrue(self~verifyMatchResult(r~group(1), 6, 7, "a"))

  r = self~find(p, "xaxaaaaxyz")
  -- this should match the full 4 characters
  self~assertTrue(self~verifyMatchResult(r, 4, 8, "aaaa"))
  self~assertTrue(self~verifyMatchResult(r~group(1), 7, 8, "a"))

  p = .Pattern~compile("ab{2,3}c")     -- repetitive in the middle
  self~assertFalse(self~matches(p, "ac"))  -- must have 2 a's
  self~assertFalse(self~matches(p, "abc"))  -- also bad
  self~assertTrue(self~matches(p, "abbc"))  -- this is good
  self~assertTrue(self~matches(p, "abbbc"))  -- should also work
  self~assertFalse(self~matches(p, "abbbbc"))  -- should fail

-- tests of the {n,} pattern modifier
::method testAtLeastCountGroupModifier
  p = .Pattern~compile("(a){3,}")     -- exactly 3 occurrances of a
  self~assertFalse(self~matches(p, ""))  -- null string should not match
  self~assertFalse(self~matches(p, "a")) -- single a should not match
  self~assertFalse(self~matches(p, "aa")) -- one less than the required
  self~assertTrue(self~matches(p, "aaa")) -- The required number
  self~assertTrue(self~matches(p, "aaaa")) -- still good

  -- a few startsWith tests.
  self~assertFalse(self~startsWith(p, ""))  -- null string should not match
  self~assertFalse(self~startsWith(p, "aa")) -- still not enough
  self~assertTrue(self~startsWith(p, "aaa")) -- this is ok
  self~assertTrue(self~startsWith(p, "aaaa")) -- as is this

  r = self~find(p, "xaaxaaaxyz")
  -- this will only match at the second grouping of a's
  self~assertTrue(self~verifyMatchResult(r, 5, 8, "aaa"))
  self~assertTrue(self~verifyMatchResult(r~group(1), 7, 8, "a"))

  r = self~find(p, "xaaxaaaaxyz")
  -- this should match the full 4 characters
  self~assertTrue(self~verifyMatchResult(r, 5, 9, "aaaa"))
  self~assertTrue(self~verifyMatchResult(r~group(1), 8, 9, "a"))

  p = .Pattern~compile("a(b){2,}c")     -- repetitive in the middle
  self~assertFalse(self~matches(p, "ac"))  -- must have 2 a's
  self~assertFalse(self~matches(p, "abc"))  -- also bad
  self~assertTrue(self~matches(p, "abbc"))  -- this is good
  self~assertTrue(self~matches(p, "abbbc"))  -- should also work

-- tests of the ^ and $ boundary markers
::method testBeginEndLine
  -- beginning of line anchor (^)
  p = .Pattern~compile("^dog")
  self~assertTrue(self~matches(p, "dog"))

  self~assertTrue(self~startsWith(p, "dog"))
  self~assertTrue(self~startsWith(p, "dog "))

  r = self~find(p, "dog")
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "dog"))

  r = self~find(p, "dog ")
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "dog"))

  r = self~find(p, " dog")
  self~assertFalse(r~matched)

  -- at the beginning of line doesn't count by default
  r = self~find(p, "0d0a"x||"dog")
  self~assertFalse(r~matched)

  -- now interactions with the mode flags
  -- this is the default, which should be the same as the above
  p = .Pattern~compile("^dog", .RegexCompiler~new(.RegexCompiler~singleLine))
  r = self~find(p, "0d0a"x||"dog")
  self~assertFalse(r~matched)
  -- this should now match, using internet linends
  p = .Pattern~compile("^dog", .RegexCompiler~new(.RegexCompiler~multiLine))
  r = self~find(p, "0d0a"x||"dog")
  self~assertTrue(self~verifyMatchResult(r, 3, 6, "dog"))
  -- internet lines should not work
  r = self~find(p, "0a"x||"dog")
  self~assertFalse(r~matched)
  -- same as above, but with an explicit option specified
  p = .Pattern~compile("^dog", .RegexCompiler~new(.RegexCompiler~multiLine .RegexCompiler~internetLines))
  r = self~find(p, "0d0a"x||"dog")
  self~assertTrue(self~verifyMatchResult(r, 3, 6, "dog"))
  -- the same, with unix linends
  p = .Pattern~compile("^dog", .RegexCompiler~new(.RegexCompiler~multiLine .RegexCompiler~unixLines))
  r = self~find(p, "0a"x||"dog")
  self~assertTrue(self~verifyMatchResult(r, 2, 5, "dog"))
  -- this works, but only indirectly because the 0d is "just data" and is
  -- ignored.  Only the 0a is significant
  r = self~find(p, "0d0a"x||"dog")
  self~assertTrue(self~verifyMatchResult(r, 3, 6, "dog"))

  -- now tests with inline flags
  p = .Pattern~compile("(?-m)^dog", .RegexCompiler~new(.RegexCompiler~multiLine))
  r = self~find(p, "0d0a"x||"dog")
  self~assertFalse(r~matched)
  -- this should now match, using internet linends
  p = .Pattern~compile("(?m)^dog", .RegexCompiler~new(.RegexCompiler~singleLine))
  r = self~find(p, "0d0a"x||"dog")
  self~assertTrue(self~verifyMatchResult(r, 3, 6, "dog"))
  -- internet lines should not work
  r = self~find(p, "0a"x||"dog")
  self~assertFalse(r~matched)
  -- same as above, but with an explicit option specified
  p = .Pattern~compile("(?m-d)^dog", .RegexCompiler~new(.RegexCompiler~singleLine .RegexCompiler~unixLines))
  r = self~find(p, "0d0a"x||"dog")
  self~assertTrue(self~verifyMatchResult(r, 3, 6, "dog"))

  -- the same, with unix linends
  p = .Pattern~compile("(?md)^dog", .RegexCompiler~new(.RegexCompiler~singleLine .RegexCompiler~internetLines))
  r = self~find(p, "0a"x||"dog")
  self~assertTrue(self~verifyMatchResult(r, 2, 5, "dog"))
  -- this works, but only indirectly because the 0d is "just data" and is
  -- ignored.  Only the 0a is significant
  r = self~find(p, "0d0a"x||"dog")
  self~assertTrue(self~verifyMatchResult(r, 3, 6, "dog"))


  p = .Pattern~compile("\Adog")
  self~assertTrue(self~matches(p, "dog"))

  self~assertTrue(self~startsWith(p, "dog"))
  self~assertTrue(self~startsWith(p, "dog "))

  r = self~find(p, "dog")
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "dog"))

  r = self~find(p, "dog ")
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "dog"))

  r = self~find(p, " dog")
  self~assertFalse(r~matched)

  -- The \A anchor only matches the real start of data.  This should not
  -- change with the various flags
  p = .Pattern~compile("(?d)\Adog")
  r = self~find(p, "0a"x||"dog")
  self~assertFalse(r~matched)
  r = self~find(p, "0d0a"x||"dog")
  self~assertFalse(r~matched)
  p = .Pattern~compile("(?md)\Adog")
  r = self~find(p, "0a"x||"dog")
  self~assertFalse(r~matched)
  r = self~find(p, "0d0a"x||"dog")
  self~assertFalse(r~matched)
  p = .Pattern~compile("(?m-d)\Adog")
  r = self~find(p, "0a"x||"dog")
  self~assertFalse(r~matched)
  r = self~find(p, "0d0a"x||"dog")
  self~assertFalse(r~matched)

  -- end of line anchor

  p = .Pattern~compile("dog$")
  self~assertTrue(self~matches(p, "dog"))
  -- This will not match if there is a linend because the pattern
  -- does not account for the characters
  self~assertFalse(self~matches(p, "dog"||"0d0a"x))

  self~assertTrue(self~startsWith(p, "dog"))
  -- however, this WILL work
  self~assertTrue(self~startsWith(p, "dog"||"0d0a"x))
  self~assertFalse(self~startsWith(p, "dog "))

  r = self~find(p, "dog")
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "dog"))
  -- the linend is not included in the match position
  r = self~find(p, "dog"||"0d0a"x)
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "dog"))

  r = self~find(p, " dog")
  self~assertTrue(self~verifyMatchResult(r, 2, 5, "dog"))

  r = self~find(p, "dog ")
  self~assertFalse(r~matched)

  -- the linends only match if they are in the end position
  r = self~find(p, "dog"||"0d0a0"x||" ")
  self~assertFalse(r~matched)
  r = self~find(p, "dog"||"0d0a00d0a"x||" ")
  self~assertFalse(r~matched)

  -- now mode tests for the end anchors.  The various option/flag
  -- combinations have been very well tested other places, so this will
  -- use a smaller set and just test the effect of those flags on the
  -- anchor patterns

  -- unix mode linends
  p = .Pattern~compile("(?d)dog$")
  r = self~find(p, "dog")
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "dog"))
  -- the linend is not included in the match position
  r = self~find(p, "dog"||"0a"x)
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "dog"))
  -- this should fail because the '0d'x follows the match string
  r = self~find(p, "dog"||"0d0a"x)
  self~assertFalse(r~matched)
  -- multi line mode
  p = .Pattern~compile("(?m)dog$")
  r = self~find(p, "dog"||"0d0a"x||"cat")
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "dog"))
  -- multi line mode with unix linends
  p = .Pattern~compile("(?md)dog$")
  r = self~find(p, "dog"||"0a"x||"cat")
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "dog"))

  -- same as the "unmoded" $.  This can handle different
  -- linends but never in multiline mode
  p = .Pattern~compile("dog\Z")
  self~assertTrue(self~matches(p, "dog"))
  -- This will not match if there is a linend because the pattern
  -- does not account for the characters
  self~assertFalse(self~matches(p, "dog"||"0d0a"x))

  self~assertTrue(self~startsWith(p, "dog"))
  self~assertTrue(self~startsWith(p, "dog"||"0d0a"x))
  self~assertFalse(self~startsWith(p, "dog "))

  r = self~find(p, "dog")
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "dog"))
  -- the linend does not show up in the match position
  r = self~find(p, "dog"||"0d0a"x)
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "dog"))

  r = self~find(p, " dog")
  self~assertTrue(self~verifyMatchResult(r, 2, 5, "dog"))

  r = self~find(p, "dog ")
  self~assertFalse(r~matched)

  -- the linends only match if they are in the end position
  r = self~find(p, "dog"||"0d0a0"x||" ")
  self~assertFalse(r~matched)
  r = self~find(p, "dog"||"0d0a00d0a"x||" ")
  self~assertFalse(r~matched)

  -- unix mode linends
  p = .Pattern~compile("(?d)dog\Z")
  r = self~find(p, "dog")
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "dog"))
  -- the linend is not included in the match position
  r = self~find(p, "dog"||"0a"x)
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "dog"))
  -- this should fail because the '0d'x follows the match string
  r = self~find(p, "dog"||"0d0a"x)
  self~assertFalse(r~matched)
  -- multi line mode...should not change the result processing
  p = .Pattern~compile("(?m)dog\Z")
  r = self~find(p, "dog"||"0d0a"x||"cat")
  self~assertFalse(r~matched)
  -- multi line mode with unix linends
  p = .Pattern~compile("(?md)dog\Z")
  r = self~find(p, "dog"||"0a"x||"cat")
  self~assertFalse(r~matched)

  -- matches only the end of text (no linend processing)
  p = .Pattern~compile("dog\z")
  self~assertTrue(self~matches(p, "dog"))
  -- This will match if there is just linend at the end
  -- of the text
  self~assertFalse(self~matches(p, "dog"||"0d0a"x))

  self~assertTrue(self~startsWith(p, "dog"))
  self~assertFalse(self~startsWith(p, "dog"||"0d0a"x))
  self~assertFalse(self~startsWith(p, "dog "))

  r = self~find(p, "dog")
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "dog"))
  -- the linend is not processed
  r = self~find(p, "dog"||"0d0a"x)
  self~assertFalse(r~matched)

  r = self~find(p, " dog")
  self~assertTrue(self~verifyMatchResult(r, 2, 5, "dog"))

  r = self~find(p, "dog ")
  self~assertFalse(r~matched)

  -- combine both start and end
  p = .Pattern~compile("^dog$")
  self~assertTrue(self~matches(p, "dog"))
  self~assertFalse(self~matches(p, " dog"))
  self~assertFalse(self~matches(p, "dog "))
  self~assertTrue(self~startsWith(p, "dog"))
  self~assertFalse(self~startsWith(p, "dog "))

  r = self~find(p, "dog")
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "dog"))

  -- these cannot match
  r = self~find(p, "dog ")
  self~assertFalse(r~matched)
  r = self~find(p, " dog")
  self~assertFalse(r~matched)

-- test the \b, \B, \<, and \> triggers
::method testWordBoundary
  p = .Pattern~compile("\bdog\b")
  r = self~find(p, "dog")
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "dog"))
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "dog"))
  r = self~find(p, " dog ")
  self~assertTrue(self~verifyMatchResult(r, 2, 5, "dog"))

  -- not word boundary
  p = .Pattern~compile("\Bdog\B")
  r = self~find(p, "dog")
  self~assertFalse(r~matched)
  r = self~find(p, " dog ")
  self~assertFalse(r~matched)
  r = self~find(p, "adogb")
  self~assertTrue(self~verifyMatchResult(r, 2, 5, "dog"))

  p = .Pattern~compile("\<dog\>")
  r = self~find(p, "dog")
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "dog"))
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "dog"))
  r = self~find(p, " dog ")
  self~assertTrue(self~verifyMatchResult(r, 2, 5, "dog"))

-- escape characters, both at top-level and inside classes
::method testEscapes
  -- escaped backslash character
  p = .Pattern~compile("\\")
  self~checkIncludedCharacters(p, "\")

  -- escaped dot character
  p = .Pattern~compile("\.")
  self~checkIncludedCharacters(p, ".")

  -- escaped dollar sign
  p = .Pattern~compile("\$")
  self~checkIncludedCharacters(p, "$")

  -- escaped caret
  p = .Pattern~compile("\^")
  self~checkIncludedCharacters(p, "^")

  -- escaped bracket
  p = .Pattern~compile("\[")
  self~checkIncludedCharacters(p, "[")

  -- escaped bracket
  p = .Pattern~compile("\]")
  self~checkIncludedCharacters(p, "]")

  -- escaped paren
  p = .Pattern~compile("\(")
  self~checkIncludedCharacters(p, "(")

  -- escaped paren
  p = .Pattern~compile("\)")
  self~checkIncludedCharacters(p, ")")

  -- escaped paren
  p = .Pattern~compile("\)")
  self~checkIncludedCharacters(p, ")")

  -- escaped brace
  p = .Pattern~compile("\{")
  self~checkIncludedCharacters(p, "{")

  -- escaped brace
  p = .Pattern~compile("\}")
  self~checkIncludedCharacters(p, "}")

  -- escaped star
  p = .Pattern~compile("\*")
  self~checkIncludedCharacters(p, "*")

  -- escaped question
  p = .Pattern~compile("\?")
  self~checkIncludedCharacters(p, "?")

  -- escaped plus
  p = .Pattern~compile("\+")
  self~checkIncludedCharacters(p, "+")

  -- escaped OR
  p = .Pattern~compile("\|")
  self~checkIncludedCharacters(p, "|")

  -- horizontal tab character
  p = .Pattern~compile("\t")
  self~checkIncludedCharacters(p, "09"x)

  -- vertical tab character
  p = .Pattern~compile("\v")
  self~checkIncludedCharacters(p, "0b"x)

  -- escape
  p = .Pattern~compile("\e")
  self~checkIncludedCharacters(p, "1b"x)

  -- form feed
  p = .Pattern~compile("\f")
  self~checkIncludedCharacters(p, "0c"x)

  -- new line
  p = .Pattern~compile("\n")
  self~checkIncludedCharacters(p, "0a"x)

  -- carriage return
  p = .Pattern~compile("\r")
  self~checkIncludedCharacters(p, "0d"x)

  -- alert (bell)
  p = .Pattern~compile("\a")
  self~checkIncludedCharacters(p, "07"x)

  -- hex value
  p = .Pattern~compile("\x20")
  self~checkIncludedCharacters(p, "20"x)

  -- one-digit octal value
  p = .Pattern~compile("\07")
  self~checkIncludedCharacters(p, "07"x)

  -- two-digit octal value
  p = .Pattern~compile("\040")
  self~checkIncludedCharacters(p, "20"x)

  -- three-digit octal value
  p = .Pattern~compile("\0100")
  self~checkIncludedCharacters(p, "40"x)

  -- the whole set as a class
  p = .Pattern~compile("[\(\[\{\\\^\-\$\|\]\}\)\?\*\+\.\a\t\e\f\n\r\v]")
  self~checkIncludedCharacters(p, "07091b0c0a0b0d"x||"([{\^-$|]})?*+.")

  -- check each of the escaped control characters
  -- check each combination and make sure it maps back
  -- to the correct combo
  do i = 1 to 26
     c = .RegexCompiler~LowerCaseCharacters~subchar(i)
     p = .Pattern~compile("\c"||c)
     self~checkIncludedCharacters(p, d2c(i))
  end
  -- both the uppercase and lowercase combinations
  do i = 1 to 26
     c = .RegexCompiler~UpperCaseCharacters~subchar(i)
     p = .Pattern~compile("\c"||c)
     self~checkIncludedCharacters(p, d2c(i))
  end

-- Named class families.  We need to test these both at the
-- top level and inside of a class specification
::method testClassFamilies
  self~verifyClassFamily("Lower", .RegexCompiler~LowerCaseCharacters)
  self~verifyClassFamily("Upper", .RegexCompiler~UpperCaseCharacters)
  self~verifyClassFamily("ASCII", xrange('00'x, '7F'x))
  self~verifyClassFamily("Alpha", .RegexCompiler~LowerCaseCharacters||.RegexCompiler~UpperCaseCharacters)
  self~verifyClassFamily("Digit", .RegexCompiler~DigitCharacters)
  self~verifyClassFamily("Alnum", .RegexCompiler~LowerCaseCharacters||.RegexCompiler~UpperCaseCharacters||.RegexCompiler~DigitCharacters)
  self~verifyClassFamily("Punct", "!""#$%&'()*+,-./:;<=>?@[\]^_`{|}~")
  self~verifyClassFamily("Graph", "!""#$%&'()*+,-./:;<=>?@[\]^_`{|}~"||.RegexCompiler~LowerCaseCharacters||.RegexCompiler~UpperCaseCharacters||.RegexCompiler~DigitCharacters)
  self~verifyClassFamily("Print", "!""#$%&'()*+,-./:;<=>?@[\]^_`{|}~"||.RegexCompiler~LowerCaseCharacters||.RegexCompiler~UpperCaseCharacters||.RegexCompiler~DigitCharacters)
  self~verifyClassFamily("Blank", "2009"x)
  self~verifyClassFamily("Cntrl", xrange("00"x, "1F"x) || "7F"x)
  self~verifyClassFamily("XDigit", "0123456789abcdefABCDEF")
  self~verifyClassFamily("ODigit", "01234567")
  self~verifyClassFamily("Space", .RegexCompiler~WhiteSpaceCharacters)
  self~verifyClassFamily("RexxSymbol", .RegexCompiler~LowerCaseCharacters||.RegexCompiler~UpperCaseCharacters||.RegexCompiler~DigitCharacters||".!?_")
  self~verifyClassFamily("RexxVariableStart", .RegexCompiler~LowerCaseCharacters||.RegexCompiler~UpperCaseCharacters||"!?_")
  self~verifyClassFamily("RexxOperator", "+-\/%*|&=<>" || 'aaac'x)
  self~verifyClassFamily("RexxSpecial", ",;:~()[]")
  -- all variants with the "Is" prefix
  self~verifyClassFamily("IsLower", .RegexCompiler~LowerCaseCharacters)
  self~verifyClassFamily("IsUpper", .RegexCompiler~UpperCaseCharacters)
  self~verifyClassFamily("IsASCII", xrange('00'x, '7F'x))
  self~verifyClassFamily("IsAlpha", .RegexCompiler~LowerCaseCharacters||.RegexCompiler~UpperCaseCharacters)
  self~verifyClassFamily("IsDigit", .RegexCompiler~DigitCharacters)
  self~verifyClassFamily("IsAlnum", .RegexCompiler~LowerCaseCharacters||.RegexCompiler~UpperCaseCharacters||.RegexCompiler~DigitCharacters)
  self~verifyClassFamily("IsPunct", "!""#$%&'()*+,-./:;<=>?@[\]^_`{|}~")
  self~verifyClassFamily("IsGraph", "!""#$%&'()*+,-./:;<=>?@[\]^_`{|}~"||.RegexCompiler~LowerCaseCharacters||.RegexCompiler~UpperCaseCharacters||.RegexCompiler~DigitCharacters)
  self~verifyClassFamily("IsPrint", "!""#$%&'()*+,-./:;<=>?@[\]^_`{|}~"||.RegexCompiler~LowerCaseCharacters||.RegexCompiler~UpperCaseCharacters||.RegexCompiler~DigitCharacters)
  self~verifyClassFamily("IsBlank", "2009"x)
  self~verifyClassFamily("IsCntrl", xrange("00"x, "1F"x) || "7F"x)
  self~verifyClassFamily("IsXDigit", "0123456789abcdefABCDEF")
  self~verifyClassFamily("IsODigit", "01234567")
  self~verifyClassFamily("IsSpace", .RegexCompiler~WhiteSpaceCharacters)
  self~verifyClassFamily("IsRexxSymbol", .RegexCompiler~LowerCaseCharacters||.RegexCompiler~UpperCaseCharacters||.RegexCompiler~DigitCharacters||".!?_")
  self~verifyClassFamily("IsRexxVariableStart", .RegexCompiler~LowerCaseCharacters||.RegexCompiler~UpperCaseCharacters||"!?_")
  self~verifyClassFamily("IsRexxOperator", "+-\/%*|&=<>" || 'aaac'x)
  self~verifyClassFamily("IsRexxSpecial", ",;:~()[]")


-- various named group tests
::method testNamedGroup
  -- very simple group
  p = .Pattern~compile("(?<foo>abc)")

  r = self~find(p, "abcabc")
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "abc"))
  self~assertTrue(self~verifyMatchResult(r~group("foo"), 1, 4, "abc"))
  -- group zero is supposed to be the same as the entire match.  Verify
  -- we get good information here.
  self~assertTrue(self~verifyMatchResult(r~group(0), r~start, r~end, r~text))

  -- now with a repetitor
  p = .Pattern~compile("(?<foo>abc)*")

  -- this should match everything
  r = self~find(p, "abcabc")
  self~assertTrue(self~verifyMatchResult(r, 1, 7, "abcabc"))
  -- should only match last group
  self~assertTrue(self~verifyMatchResult(r~group("foo"), 4, 7, "abc"))

  -- test with multiple groups
  p = .Pattern~compile("(?<foo>a)(?<bar>b)")
  r = self~find(p, "abcabc")
  -- this should match "ab"
  self~assertTrue(self~verifyMatchResult(r, 1, 3, "ab"))
  -- now verify each group

  -- group zero is always the main match
  self~assertTrue(self~verifyMatchResult(r~group(0), 1, 3, "ab"))
  self~assertTrue(self~verifyMatchResult(r~group("foo"), 1, 2, "a"))
  self~assertTrue(self~verifyMatchResult(r~group("bar"), 2, 3, "b"))


  -- test with reused names
  p = .Pattern~compile("(?<foo>a)(?<foo>b)")
  r = self~find(p, "abcabc")
  -- this should match "ab"
  self~assertTrue(self~verifyMatchResult(r, 1, 3, "ab"))
  -- now verify each group

  -- group zero is always the main match, foo will be the
  -- last usage
  self~assertTrue(self~verifyMatchResult(r~group(0), 1, 3, "ab"))
  self~assertTrue(self~verifyMatchResult(r~group("foo"), 2, 3, "b"))

-- variations of "this OR that"
::method testAlternation
  p = .Pattern~compile("a|b")

  -- either of these will do
  self~assertTrue(self~matches(p, "a"))
  self~assertTrue(self~matches(p, "b"))
  self~assertFalse(self~matches(p, "c"))

  self~assertTrue(self~startsWith(p, "abc"))
  self~assertTrue(self~startsWith(p, "bac"))

  r = self~find(p, "xxxabcxxx")
  self~assertTrue(self~verifyMatchResult(r, 4, 5, "a"))
  r = self~find(p, "xxxbacxxx")
  self~assertTrue(self~verifyMatchResult(r, 4, 5, "b"))


  p = .Pattern~compile("a|b|c")

  -- either of these will do
  self~assertTrue(self~matches(p, "a"))
  self~assertTrue(self~matches(p, "b"))
  self~assertTrue(self~matches(p, "c"))
  self~assertFalse(self~matches(p, "d"))

  self~assertTrue(self~startsWith(p, "abc"))
  self~assertTrue(self~startsWith(p, "bac"))
  self~assertTrue(self~startsWith(p, "cba"))

  r = self~find(p, "xxxabcxxx")
  self~assertTrue(self~verifyMatchResult(r, 4, 5, "a"))
  r = self~find(p, "xxxbacxxx")
  self~assertTrue(self~verifyMatchResult(r, 4, 5, "b"))
  r = self~find(p, "xxxcbaxxx")
  self~assertTrue(self~verifyMatchResult(r, 4, 5, "c"))

  -- test that a trailing "|" means match anything
  p = .Pattern~compile("(a|b|)xyz")

  self~assertTrue(self~matches(p, "axyz"))
  self~assertTrue(self~matches(p, "bxyz"))
  self~assertTrue(self~matches(p, "xyz"))
  self~assertFalse(self~matches(p, "cxyz"))

::method testLookArounds
  -- positive lookahead
  p = .Pattern~compile("abc(?=def)")
  self~assertTrue(self~startsWith(p, "abcdefghi"))

  -- only the abc followed by def will match, but the
  -- match position will just be the first part
  r = self~find(p, "abcabcdef")
  self~assertTrue(self~verifyMatchResult(r, 4, 7, "abc"))

  -- negative lookahead
  p = .Pattern~compile("abc(?!def)")
  self~assertTrue(self~startsWith(p, "abcabcdef"))

  -- only the abc NOT followed by def will match, but the
  -- match position will just be the first part
  r = self~find(p, "abcdefabcghi")
  self~assertTrue(self~verifyMatchResult(r, 7, 10, "abc"))

  -- positive look behind
  p = .Pattern~compile("(?<=def)abc")

  r = self~find(p, "abcdefabc")
  self~assertTrue(self~verifyMatchResult(r, 7, 10, "abc"))

  -- negative look behind
  p = .Pattern~compile("(?<!def)abc")

  r = self~find(p, "defabcabc")
  self~assertTrue(self~verifyMatchResult(r, 7, 10, "abc"))

::method testNonCapturingGroup
  -- test with multiple groups
  p = .Pattern~compile("((a)(?:b(c)))")
  r = self~find(p, "abcabc")
  -- this should match "abc"
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "abc"))
  -- now verify each of the groups 0-3.  The non-capturing
  -- group is no longer in the mix

  -- group zero is always the main match
  self~assertTrue(self~verifyMatchResult(r~group(0), 1, 4, "abc"))
  -- ((a)(b(c))))
  self~assertTrue(self~verifyMatchResult(r~group(1), 1, 4, "abc"))
  -- (a)
  self~assertTrue(self~verifyMatchResult(r~group(2), 1, 2, "a"))
  -- (b(c))  Would have been group 3 originally, but since it was
  -- made non-capturing, the "c" group is now #3
  -- self~assertTrue(self~verifyMatchResult(r~group(2), 2, 4, "bc"))
  -- (c)
  self~assertTrue(self~verifyMatchResult(r~group(3), 3, 4, "c"))

-- tests of \Q \E string quoting
::method testQuoting
  -- whole bunch of characters normally needing escapes as a single
  -- quoted string.  This should match exactly
  p = .Pattern~compile("\Q([{\^-$|]})?*+.\a\t\e\f\n\r\v\E")
  self~assertTrue(self~matches(p, "([{\^-$|]})?*+.\a\t\e\f\n\r\v"))

-- Some simple tests or atomic grouping.
::method testAtomicGrouping
  -- example from http://www.regular-expressions.info/atomic.html
  -- this match should work when applied to "insert"
  p = .Pattern~compile("\b(?>integer|insert|in)\b")
  self~assertTrue(self~matches(p, "insert"))

  -- this one will fail because the "in" will match first, which
  -- will terminate all the rest of the alternative checks.
  p = .Pattern~compile("\b(?>in|insert|integer)\b")
  self~assertFalse(self~matches(p, "insert"))

-- embedded comments in a pattern
::method testComment
  p = .Pattern~compile("abc(?# This is a comment)def")
  self~assertTrue(self~matches(p, "abcdef"))

-- conditional patterns
::method testConditional
  p = .Pattern~compile("(abc)?(?(1)def)")
  -- The def will be found because the abc group matched
  r = self~find(p, "abcdef")
  self~assertTrue(self~verifyMatchResult(r, 1, 7, "abcdef"))
  -- abc did not, so the def is never checked.  The else is
  -- to match nothing, so this should be a zero-length patch at the
  -- beginning of the string
  r = self~find(p, "def")
  self~assertTrue(self~verifyMatchResult(r, 1, 1, ""))

  -- * pattern.  The will match twice
  p = .Pattern~compile("(abc)*(?(1)def)")
  r = self~find(p, "abcabcdef")
  self~assertTrue(self~verifyMatchResult(r, 1, 10, "abcabcdef"))

  -- and a repetive one pattern.  The will match twice
  p = .Pattern~compile("(abc){2}(?(1)def)")
  r = self~find(p, "abcabcdef")
  self~assertTrue(self~verifyMatchResult(r, 1, 10, "abcabcdef"))

  -- named group
  p = .Pattern~compile("(?<foo>abc)?(?(foo)def)")
  -- The def will be found because the abc group matched
  r = self~find(p, "abcdef")
  self~assertTrue(self~verifyMatchResult(r, 1, 7, "abcdef"))

  -- real example from
  -- http://php.net/manual/en/regexp.reference.conditional.php
  -- searchs for a set of characters optionally surrounded by
  -- parens
  p = .Pattern~compile("(\()?[^()]+(?(1)\))")
  self~assertTrue(self~matches(p, "abcabcdef"))
  self~assertTrue(self~matches(p, "(abcabcdef)"))
  self~assertFalse(self~matches(p, "(abcabcdef"))

  -- another example from the same website.  Uses a lookahead to see if there
  -- is a letter following the current position.  If there is, then it looks for
  -- the pattern dd-aaa-ddd, otherwise looks for dd-dd-dd
  p = .Pattern~compile("(?(?=[^a-z]*[a-z])\d{2}-[a-z]{3}-\d{2}|\d{2}-\d{2}-\d{2})")

  self~assertTrue(self~matches(p, "12-abc-34"))
  self~assertTrue(self~matches(p, "12-34-56"))

  -- same thing, only using a negative assertion with the conditions reversed
  p = .Pattern~compile("(?(?![^a-z]*[a-z])\d{2}-\d{2}-\d{2}|\d{2}-[a-z]{3}-\d{2})")

  self~assertTrue(self~matches(p, "12-abc-34"))
  self~assertTrue(self~matches(p, "12-34-56"))

  -- similar, but uses a lookbehind to see which to use
  p = .Pattern~compile("(1|2)(?(?<=1)\d{2}-\d{2}-\d{2}|\d{2}-[a-z]{3}-\d{2})")

  self~assertTrue(self~matches(p, "212-abc-34"))
  self~assertTrue(self~matches(p, "112-34-56"))
  -- the reverse situation should fail
  self~assertFalse(self~matches(p, "112-abc-34"))
  self~assertFalse(self~matches(p, "212-34-56"))

  -- similar, but uses a negative lookbehind to see which to use
  -- NOTE:  the conditions are swapped
  p = .Pattern~compile("(1|2)(?(?<!1)\d{2}-\d{2}-\d{2}|\d{2}-[a-z]{3}-\d{2})")

  self~assertTrue(self~matches(p, "112-abc-34"))
  self~assertTrue(self~matches(p, "212-34-56"))
  -- the reverse situation should fail
  self~assertFalse(self~matches(p, "212-abc-34"))
  self~assertFalse(self~matches(p, "112-34-56"))

-- email registered pattern
::method testEmail
  p = .Pattern~compile("^\m{email}$")
  self~assertTrue(self~matches(p, "postmaster@oorexx.org"))
  r = self~find(p, "postmaster@oorexx.org")
  self~assertTrue(self~verifyMatchResult(r, 1, "postmaster@oorexx.org"~length + 1, "postmaster@oorexx.org"))
  re = r~group(0)~result("email")
  self~assertTrue(self~verifyMatchResult(re, 1, "postmaster@oorexx.org"~length + 1, "postmaster@oorexx.org"))
  self~assertTrue(self~verifyMatchResult(re~group("username"), 1, "postmaster"~length + 1, "postmaster"))
  self~assertTrue(self~verifyMatchResult(re~group("domain"), 12, 12 + "oorexx.org"~length, "oorexx.org"))

  -- some tests for the [] method on a match result
  self~assertEquals("postmaster@oorexx.org", r[])
  self~assertEquals("postmaster", re["username"])

::method testBackReference


  -- numbered group
  p = .Pattern~compile("(abc)\1")
  -- This should match twice
  r = self~find(p, "abcabc")
  self~assertTrue(self~verifyMatchResult(r, 1, 7, "abcabc"))
  self~assertTrue(self~verifyMatchResult(r~group("1"), 1, 4, "abc"))

  -- numbered group, fully qualified back reference sequence
  p = .Pattern~compile("(abc)\k<1>")
  -- This should match twice
  r = self~find(p, "abcabc")
  self~assertTrue(self~verifyMatchResult(r, 1, 7, "abcabc"))
  self~assertTrue(self~verifyMatchResult(r~group("1"), 1, 4, "abc"))

  -- named group
  p = .Pattern~compile("(?<foo>abc)\k<foo>)")
  -- This should match twice
  r = self~find(p, "abcabc")
  self~assertTrue(self~verifyMatchResult(r, 1, 7, "abcabc"))
  self~assertTrue(self~verifyMatchResult(r~group("Foo"), 1, 4, "abc"))

  -- case insensitive names
  p = .Pattern~compile("(?<foo>abc)\k<FOO>)")
  -- This should match twice
  r = self~find(p, "abcabc")
  self~assertTrue(self~verifyMatchResult(r, 1, 7, "abcabc"))
  self~assertTrue(self~verifyMatchResult(r~group("Foo"), 1, 4, "abc"))

  compiler = .RegexCompiler~new
  compiler~registerNamedPattern("abc", "(?<foo>bar)")
  p = .Pattern~compile("\m{abc}\k<0{abc}>", compiler)
  -- should match everything
  r = self~find(p, "barbar")
  self~assertTrue(self~verifyMatchResult(r, 1, 7, "barbar"))
  -- same as above, but the group is defaulted
  p = .Pattern~compile("\m{abc}\k<{abc}>", compiler)
  -- should match everything
  r = self~find(p, "barbar")
  self~assertTrue(self~verifyMatchResult(r, 1, 7, "barbar"))

  -- same, but the back reference path goes one level deeper
  p = .Pattern~compile("\m{abc}\k<{abc<foo>}>", compiler)
  -- should match everything
  r = self~find(p, "barbar")
  self~assertTrue(self~verifyMatchResult(r, 1, 7, "barbar"))

-- test various boundary conditions using generalized class definitions
::method testClassBoundary
  -- abc ending at a boundary of bc
  p = .Pattern~compile("abc(?b[bc])")
  r = self~find(p, "abcd")
  self~assertTrue(self~verifyMatchResult(r, 1, 4, "abc"))
  -- not on the correct boundary
  r = self~find(p, "abcc")
  self~assertFalse(r~matched)
  -- bracketed by boundary conditions
  p = .Pattern~compile("(?b[123])abc(?b[456])")
  r = self~find(p, "1abc6")
  self~assertTrue(self~verifyMatchResult(r, 2, 5, "abc"))
  -- the boundaries are in the match string
  p = .Pattern~compile("(?b[abc])abc(?b[cde])")
  r = self~find(p, "1abc6")
  self~assertTrue(self~verifyMatchResult(r, 2, 5, "abc"))
  -- negated boundaries
  p = .Pattern~compile("(?b^[bc])abc(?b^[de])")
  -- will work because
  r = self~find(p, "aabcc")
  self~assertTrue(self~verifyMatchResult(r, 2, 5, "abc"))
  -- will fail because the boundaries are there
  r = self~find(p, "babcd")
  self~assertFalse(r~matched)



Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:





No, thanks