/******************************************************************************
 test.cc

	A test program for JRegex.  Designed to test my code, not Spencer's.

	Copyright © 1997 by Dustin Laurence.  All rights reserved.
	
	Base code generated by Codemill v0.1.0

	* The test framework isn't yet ready for patterns or strings containing NULL.

 *****************************************************************************/

#include <iostream.h>

#include <JRegex.h>
#include <JUserNotification.h>
#include <JCreateProgressDisplay.h>
#include <JError.h>
#include <JString.h>
#include <JIndexRange.h>

#include <jAssert.h>

	void ShouldCompile(const JSize LINE, JRegex& regex, const JCharacter* pattern);
	void ShouldNotCompile(const JSize LINE, JRegex& regex, const JCharacter* pattern);

	void ShouldCompile(const JSize LINE, JRegex& regex, const JCharacter* pattern,
	                   const JSize length, const JSize nullCount);
	void ShouldNotCompile(const JSize LINE, JRegex& regex, const JCharacter* pattern,
	                   const JSize length);

	void ShouldSwitch(const JSize LINE, JRegex& regex, const JRegex::Dialect dialect);
	void ShouldNotSwitch(const JSize LINE, JRegex& regex, const JRegex::Dialect dialect);

	void ShouldMatch(const JSize LINE, JRegex& regex, const JCharacter* string,
	                 const JCharacter* compareString);
	void ShouldNotMatch(const JSize LINE, JRegex& regex, const JCharacter* string);

	void MatchShouldBe(const JSize LINE, const JCharacter* compareString);
	void IntShouldBe(const JSize LINE, const JInteger anInt, const JInteger expecting);

	void Assert(const JSize LINE, const int test);
	void Assert(const JSize LINE, const int test, const JCharacter* description);
	inline void Assert(const JSize LINE, const JError& err, const JCharacter* description)
		{ Assert(LINE, err.OK(), description); };

	void ShouldMatchFrom(const JSize LINE, JRegex& regex, const JCharacter* string,
	                      const JSize offset, const JCharacter* compareString);
	void ShouldNotMatchFrom(const JSize LINE, JRegex& regex, const JCharacter* string,
	                        const JSize offset);

	void ShouldMatchAfter(const JSize LINE, JRegex& regex, const JCharacter* string,
	                      const JIndexRange& before, const JCharacter* compareString);
	void ShouldNotMatchAfter(const JSize LINE, JRegex& regex, const JCharacter* string,
	                      const JIndexRange& before);

	void ShouldMatchWithin(const JSize LINE, JRegex& regex, const JCharacter* string,
	                      const JIndexRange& range, const JCharacter* compareString);
	void ShouldNotMatchWithin(const JSize LINE, JRegex& regex, const JCharacter* string,
	                      const JIndexRange& range);

	void ShouldMatchLastWithin(const JSize LINE, JRegex& regex, const JCharacter* string,
	                      const JIndexRange& range, const JCharacter* compareString,
	                      const JSize matchCount);
	void ShouldNotMatchLastWithin(const JSize LINE, JRegex& regex, const JCharacter* string,
	                      const JIndexRange& range);

	void ShouldMatchBackward(const JSize LINE, JRegex& regex, const JCharacter* string,
	                      const JSize offset, const JCharacter* compareString);
	void ShouldNotMatchBackward(const JSize LINE, JRegex& regex, const JCharacter* string,
	                        const JSize offset);


	const JCharacter* gPattern = NULL;
	JSize             gLength = 0;
//	const JCharacter* gString = NULL;
	JString gString;
	JIndexRange      gMatch;
	const JSize           matchArraySize = 10;
	JIndexRange          gMatchArray[matchArraySize];
	JArray<JIndexRange>* gMatchList = NULL;

/******************************************************************************
 main

 *****************************************************************************/

int
main()
{
	gMatchList = new JArray<JIndexRange>;
	assert(gMatchList != NULL);

	cout << "\nJRegex bug check: only errors will be reported, so no news is good news." << endl;

// Test constructors
	JRegex *regexList[2];
	JRegex regex("c");
	JRegex regex2;
	Assert(__LINE__, regex.GetSubCount() == 0, "GetSubCount failed");

// Ensure that an immediate restore works
	regex.RestoreDefaults();
	regex2.RestoreDefaults();

//	regex2.Match("c"); // Test match without compile: should assert

// Test whether dialect works:
	ShouldSwitch(__LINE__, regex, JRegex::kExtended);
	Assert(__LINE__, regex.GetDialect() == JRegex::kExtended);
	ShouldCompile(__LINE__, regex, "a+x*b+");
	Assert(__LINE__, regex.GetSubCount() == 0, "GetSubCount failed");

	regex2 = regex; // Do a little assignment checking too

	regexList[0] = &regex;
	regexList[1] = &regex2;
	JIndex i; // Don't declare in header to support M'werks obsolete behavior!
	for (i=0;i<2;i++)
		{
		ShouldNotMatch(__LINE__, *regexList[i], "qqqqqa+x*b+qqqqqq");
		ShouldNotMatch(__LINE__, *regexList[i], "a+xxxxb+");
		ShouldMatch(__LINE__, *regexList[i], "axxxb", "axxxb");
		ShouldNotMatch(__LINE__, *regexList[i], "xxxxxxxxb");
		ShouldMatch(__LINE__, *regexList[i], "aaabb", "aaabb");
		ShouldNotMatch(__LINE__, *regexList[i], "aaaxxx");
		ShouldMatch(__LINE__, *regexList[i], "aaaabbb", "aaaabbb");
		}

	// Note that the transparent re-compilation has to work for this set to work
	ShouldSwitch(__LINE__, regex, JRegex::kLiteral);
	Assert(__LINE__, regex.GetDialect() == JRegex::kLiteral);
	ShouldMatch(__LINE__, regex, "qqqqqa+x*b+qqqqqq", "a+x*b+");
	ShouldNotMatch(__LINE__, regex, "a+xxxxb+");
	ShouldNotMatch(__LINE__, regex, "axxxb");

	ShouldSwitch(__LINE__, regex, JRegex::kBasic);
	Assert(__LINE__, regex.GetDialect() == JRegex::kBasic);
	ShouldNotMatch(__LINE__, regex, "qqqqqa+x*b+qqqqqq");
	ShouldMatch(__LINE__, regex, "a+xxxxb+", "a+xxxxb+");
	ShouldNotMatch(__LINE__, regex,"axxxb");

// Test kUncompiled state
	ShouldSwitch(__LINE__, regex, JRegex::kLiteral);
	Assert(__LINE__, regex.GetDialect() == JRegex::kLiteral);
	ShouldCompile(__LINE__, regex, "a{1,");
	ShouldNotSwitch(__LINE__, regex, JRegex::kExtended);
	Assert(__LINE__, regex.GetDialect() == JRegex::kExtended);
	ShouldSwitch(__LINE__, regex, JRegex::kLiteral);
	Assert(__LINE__, regex.GetDialect() == JRegex::kLiteral);
	ShouldMatch(__LINE__, regex, "-----------a{1,-------------", "a{1,");

// Test case-sensitivity
	ShouldCompile(__LINE__, regex, "aBc");
	regex.RestoreDefaults();
	Assert(__LINE__,  regex.IsCaseSensitive() );
	ShouldMatch(__LINE__, regex, "qqqqqqqqqqaBcqqqqq", "aBc");
	ShouldNotMatch(__LINE__, regex, "qqqqqqqqqqabcqqqqq");

	regex.SetCaseSensitive(kFalse);
	Assert(__LINE__,  !regex.IsCaseSensitive() );
	ShouldMatch(__LINE__, regex, "qqqqqqqqqqaBcqqqqq", "aBc");
	ShouldMatch(__LINE__, regex, "qqqqqqqqqqabcqqqqq", "abc");

// Test single line
	ShouldCompile(__LINE__, regex, "^aBc");
	regex.RestoreDefaults();
	Assert(__LINE__,  !regex.IsSingleLine() );
	regex.SetSingleLine(kTrue);
	Assert(__LINE__,  regex.IsSingleLine() );
	ShouldMatch(__LINE__, regex, "aBc", "aBc");
	ShouldNotMatch(__LINE__, regex, "\naBc");

	regex.SetSingleLine(kFalse);
	Assert(__LINE__,  !regex.IsSingleLine() );
	ShouldMatch(__LINE__, regex, "aBc", "aBc");
	ShouldMatch(__LINE__, regex, "\naBc", "aBc");

// Test line begin
	regex.RestoreDefaults();
	ShouldMatch(__LINE__, regex, "aBc", "aBc");

	regex.SetLineBegin(kFalse);
	Assert(__LINE__,  !regex.IsLineBegin() );
	ShouldNotMatch(__LINE__, regex, "aBc");

// Test line end
	ShouldCompile(__LINE__, regex, "aBc$");
	regex.RestoreDefaults();
	Assert(__LINE__,  regex.IsLineEnd() );
	ShouldMatch(__LINE__, regex, "aBc", "aBc");

	regex.SetLineEnd(kFalse);
	Assert(__LINE__,  !regex.IsLineEnd() );
	ShouldNotMatch(__LINE__, regex, "aBc");

// Test single line again
	regex.SetSingleLine(kFalse);
	Assert(__LINE__,  !regex.IsSingleLine() );
	ShouldNotMatch(__LINE__, regex, "aBc");
	ShouldMatch(__LINE__, regex, "aBc\n", "aBc");

// Test error stuff
	regex.RestoreDefaults();
	ShouldNotCompile(__LINE__, regex, "(ab");
	ShouldNotCompile(__LINE__, regex, "ab{1,");

// Test dialect switching errors
	ShouldSwitch(__LINE__, regex, JRegex::kBasic);
	Assert(__LINE__, regex.GetDialect() == JRegex::kBasic);
	ShouldCompile(__LINE__, regex, "(ab");
	ShouldNotSwitch(__LINE__, regex, JRegex::kExtended);
	Assert(__LINE__, regex.GetDialect() == JRegex::kExtended);
//	ShouldMatch(__LINE__, regex, "foo", "foo"); // Test failed recompilation--should assert

// Test MatchFrom, MatchAfter
	ShouldCompile(__LINE__, regex, "x");
	regex.RestoreDefaults();
	gString = "12345678xx1234568901";

	ShouldMatch(__LINE__, regex, gString, "x");
	JInteger offset = gMatch.last;
	IntShouldBe(__LINE__, offset, 9);
	IntShouldBe(__LINE__, offset, gMatch.last );

	JIndexRange temp = gMatch;
	ShouldMatchFrom(__LINE__, regex, gString, offset+1, "x");
	IntShouldBe(__LINE__, gMatch.first, 10);
	IntShouldBe(__LINE__, gMatch.last, 10 );
	ShouldMatchAfter(__LINE__, regex, gString, temp, "x");
	IntShouldBe(__LINE__, gMatch.first, 10);
	IntShouldBe(__LINE__, gMatch.last, 10 );

	gString = "12345678x01234568901";
	ShouldNotMatchFrom(__LINE__, regex, gString, offset+1);
	IntShouldBe(__LINE__, gMatch.first, 10);
	IntShouldBe(__LINE__, gMatch.last, 10 );
	ShouldNotMatchAfter(__LINE__, regex, gString, temp);
	IntShouldBe(__LINE__, gMatch.first, 10);
	IntShouldBe(__LINE__, gMatch.last, 10);

// Test MatchWithin, MatchLastWithin, MatchAllWithin

	gString = "x234y678901234a6b";
	ShouldCompile(__LINE__, regex, "[a-z]");
	ShouldMatchWithin(__LINE__, regex, gString, JIndexRange(1, 1), "x");
	ShouldMatchWithin(__LINE__, regex, gString, JIndexRange(1, 8), "x");
	ShouldMatchWithin(__LINE__, regex, gString, JIndexRange(2, 6), "y");
	ShouldMatchWithin(__LINE__, regex, gString, JIndexRange(16, 17), "b");
	ShouldMatchWithin(__LINE__, regex, gString, JIndexRange(17, 17), "b");

	ShouldNotMatchWithin(__LINE__, regex, gString, JIndexRange(2, 4) );
	ShouldNotMatchWithin(__LINE__, regex, gString, JIndexRange(7, 14) );
	ShouldNotMatchWithin(__LINE__, regex, gString, JIndexRange(16, 16) );
	ShouldNotMatchWithin(__LINE__, regex, gString, JIndexRange(1, 0) );
	ShouldNotMatchWithin(__LINE__, regex, gString, JIndexRange(0, 0) );
	ShouldNotMatchWithin(__LINE__, regex, gString, JIndexRange(2, 1) );
	ShouldNotMatchWithin(__LINE__, regex, gString, JIndexRange(18, 17) );

	ShouldMatchLastWithin(__LINE__, regex, gString, JIndexRange(1, 4), "x", 1);
	ShouldMatchLastWithin(__LINE__, regex, gString, JIndexRange(1, 14), "y", 2);
	ShouldMatchLastWithin(__LINE__, regex, gString, JIndexRange(1, 16), "a", 3);
	ShouldMatchLastWithin(__LINE__, regex, gString, JIndexRange(1, 17), "b", 4);
	ShouldMatchLastWithin(__LINE__, regex, gString, JIndexRange(15, 15), "a", 1);
	ShouldMatchLastWithin(__LINE__, regex, gString, JIndexRange(3, 16), "a", 2);

	ShouldNotMatchLastWithin(__LINE__, regex, gString, JIndexRange(2, 4) );
	ShouldNotMatchLastWithin(__LINE__, regex, gString, JIndexRange(7, 14) );
	ShouldNotMatchLastWithin(__LINE__, regex, gString, JIndexRange(16, 16) );
	ShouldNotMatchLastWithin(__LINE__, regex, gString, JIndexRange(1, 0) );
	ShouldNotMatchLastWithin(__LINE__, regex, gString, JIndexRange(2, 1) );
	ShouldNotMatchLastWithin(__LINE__, regex, gString, JIndexRange(18, 17) );

// Test compile in a range, patterns and strings containing NULL

	// Non-null terminated, matches 'a\0b';
//	JCharacter pattern[] = {'a', '\0', 'b'};

// Test MatchAll, MatchAllWithin

	gString = "1---23asdf4s5";
	regex.RestoreDefaults();
	ShouldCompile(__LINE__, regex, "[0-9]");
	IntShouldBe(__LINE__, regex.MatchAll(gString), 5);

	IntShouldBe(__LINE__, regex.MatchAll(gString, gMatchArray, matchArraySize), 5);
	Assert(__LINE__, gString.GetSubstring(gMatchArray[0]) == "1");
	Assert(__LINE__, gString.GetSubstring(gMatchArray[1]) == "2");
	Assert(__LINE__, gString.GetSubstring(gMatchArray[2]) == "3");
	Assert(__LINE__, gString.GetSubstring(gMatchArray[3]) == "4");
	Assert(__LINE__, gString.GetSubstring(gMatchArray[4]) == "5");
	for (i=5;i<matchArraySize;i++)
		{
		Assert(__LINE__, gMatchArray[i].IsNothing() );
		}

	IntShouldBe(__LINE__, regex.MatchAll(gString, gMatchList), 5);
	Assert(__LINE__, gMatchList->GetElementCount() == 5);
	Assert(__LINE__, gString.GetSubstring(gMatchList->GetElement(1)) == "1");
	Assert(__LINE__, gString.GetSubstring(gMatchList->GetElement(2)) == "2");
	Assert(__LINE__, gString.GetSubstring(gMatchList->GetElement(3)) == "3");
	Assert(__LINE__, gString.GetSubstring(gMatchList->GetElement(4)) == "4");
	Assert(__LINE__, gString.GetSubstring(gMatchList->GetElement(5)) == "5");

	IntShouldBe(__LINE__, regex.MatchAllWithin(gString, JIndexRange(2, 12), gMatchList), 3);
	Assert(__LINE__, gMatchList->GetElementCount() == 3);
	Assert(__LINE__, gString.GetSubstring(gMatchList->GetElement(1)) == "2");
	Assert(__LINE__, gString.GetSubstring(gMatchList->GetElement(2)) == "3");
	Assert(__LINE__, gString.GetSubstring(gMatchList->GetElement(3)) == "4");

	gString = "sdjfhldfhfklajfdskldfjhasklfdhfd";
	IntShouldBe(__LINE__, regex.MatchAll(gString), 0);

	IntShouldBe(__LINE__, regex.MatchAll(gString, gMatchArray, matchArraySize), 0);
	for (i=0;i<matchArraySize;i++)
		{
		Assert(__LINE__, gMatchArray[i].IsNothing() );
		}

	IntShouldBe(__LINE__, regex.MatchAll(gString, gMatchList), 0);
	Assert(__LINE__, gMatchList->GetElementCount() == 0);

// Test parenthesis capturing, replacement

	ShouldCompile(__LINE__, regex, "a([IJ])([XY]+)b");
	Assert(__LINE__, regex.GetSubCount() == 2, "GetSubCount failed");
	gString = "-------------aJYYYb-----------";
	regex.Match(gString, gMatchArray, matchArraySize);
	Assert(__LINE__, gString.GetSubstring(gMatchArray[0]) == "aJYYYb");
	Assert(__LINE__, gString.GetSubstring(gMatchArray[1]) == "J");
	Assert(__LINE__, gString.GetSubstring(gMatchArray[2]) == "YYY");
	for (i=3;i<matchArraySize;i++)
		{
		Assert(__LINE__, gMatchArray[i].IsNothing() );
		}

	regex.Match(gString, gMatchList);
	Assert(__LINE__, gMatchList->GetElementCount() == 3);
	Assert(__LINE__, gString.GetSubstring(gMatchList->GetElement(1)) == "aJYYYb");
	Assert(__LINE__, gString.GetSubstring(gMatchList->GetElement(2)) == "J");
	Assert(__LINE__, gString.GetSubstring(gMatchList->GetElement(3)) == "YYY");

	// What if some subexpressions don't match?
	ShouldCompile(__LINE__, regex, "(a)(WontMatch)?(J)");
	Assert(__LINE__, regex.GetSubCount() == 3, "GetSubCount failed");
	regex.Match(gString, gMatchList);
	Assert(__LINE__, gMatchList->GetElementCount() == 4);
	Assert(__LINE__, gString.GetSubstring(gMatchList->GetElement(1)) == "aJ");
	Assert(__LINE__, gString.GetSubstring(gMatchList->GetElement(2)) == "a");
	Assert(__LINE__, gMatchList->GetElement(3).IsNothing() );
	Assert(__LINE__, gString.GetSubstring(gMatchList->GetElement(4)) == "J");

	ShouldCompile(__LINE__, regex, "^(x*)|(a)");
	Assert(__LINE__, regex.GetSubCount() == 2, "GetSubCount failed");
	regex.Match("bb", gMatchList);
	Assert(__LINE__, gMatchList->GetElementCount() == 3);
	Assert(__LINE__, gMatchList->GetElement(1).Is(1,0) );
	Assert(__LINE__, gString.GetSubstring(gMatchList->GetElement(1)) == "");
	Assert(__LINE__, gMatchList->GetElement(2).Is(1,0) );
	Assert(__LINE__, gString.GetSubstring(gMatchList->GetElement(2)) == "");
	Assert(__LINE__, gMatchList->GetElement(3).IsNothing() );

	// Test replacement

	{
		const JString buffer = "        DRegex::Replace(      ";

		JString thisBuffer = buffer; // Don't modify buffer so we can reuse it.
		ShouldCompile(__LINE__, regex, "D([[:alnum:]_]+)::([[:alnum:]_]+)");

		JString replacePattern = "J$1::$002";
		Assert(__LINE__, regex.SetReplacePattern(replacePattern), "SetReplacePattern failed");
		Assert(__LINE__, regex.Match(thisBuffer, gMatchList), "Match failed");
		Assert(__LINE__, gMatchList->GetElement(1).Is(9, 23), "Located range incorrect");
		JString replacedString = regex.InterpolateMatches(thisBuffer, *gMatchList);
		Assert(__LINE__, replacedString == "JRegex::Replace",
		       "Interpolation failed, actual string is \"" + replacedString + "\"");

		Assert(__LINE__, !(regex.SetReplacePattern("$$1")).OK(), "SetReplacePattern succeeded incorrectly");

		replacePattern = "\\$a \\$- \\$ $00 $1 $+2 '$+3' '$9' \"$-1\" $-2 "
		               "$-3 '$-4' '$-10' \\$";
		Assert(__LINE__, regex.SetReplacePattern(replacePattern), "SetReplacePattern failed");
		replacedString = regex.InterpolateMatches(thisBuffer, *gMatchList);

		const JString expectedString = "$a $- $ DRegex::Replace Regex Replace '' '' \"Replace\" "
		                 "Regex DRegex::Replace '' '' $";
		Assert(__LINE__, replacedString == expectedString,
		       "Interpolation failed; expected\n      \"" + expectedString
		       + "\n\" actual string was\n      \"" + replacedString + "\"");

		replacePattern = "J" "$+0001::" "$-1";
		Assert(__LINE__, regex.SetReplacePattern(replacePattern), "SetReplacePattern failed");
		// Test regular form of replace with replacement
		regex.SetLiteralReplace(kFalse);
		JIndexRange newRange;
		regex.Replace(&thisBuffer, *gMatchList, &newRange);
		Assert(__LINE__, thisBuffer == "        JRegex::Replace(      ", "Replace failed");
		Assert(__LINE__, newRange == gMatchList->GetElement(1), "Range report incorrect");
		// Test regular form of replace without replacement
		thisBuffer = buffer;
		regex.SetLiteralReplace();
		regex.Replace(&thisBuffer, *gMatchList, &newRange);
		Assert(__LINE__, thisBuffer == "        J" "$+0001::" "$-1(      ", "Replace failed");
		// Test shorthand
		thisBuffer = buffer;
		regex.Replace(&thisBuffer, gMatchList->GetElement(1), &newRange);
		Assert(__LINE__, thisBuffer == "        J" "$+0001::" "$-1(      ", "Replace failed");


		// Test ajacent replacement

		thisBuffer = " XabX ";
		ShouldCompile(__LINE__, regex, "X(a)(b)X");
		replacePattern = "$2$3$0$-4$1";

		Assert(__LINE__, regex.SetReplacePattern(replacePattern), "SetReplacePattern failed");
		Assert(__LINE__, regex.Match(thisBuffer, gMatchList), "Match failed");

		Assert(__LINE__, gMatchList->GetElementCount() == 3, "Range count incorrect");
		Assert(__LINE__, gMatchList->GetElement(1).Is(2, 5), "Located range incorrect");
		Assert(__LINE__, gMatchList->GetElement(2).Is(3, 3), "Located range incorrect");
		Assert(__LINE__, gMatchList->GetElement(3).Is(4, 4), "Located range incorrect");

		regex.SetLiteralReplace(kFalse);
		regex.Replace(&thisBuffer, *gMatchList, &newRange);
		Assert(__LINE__, newRange.Is(2, 7), "Range report incorrect");
		Assert(__LINE__, thisBuffer == " bXabXa ",
		       "Replaced string was \"" + thisBuffer + "\", should have been \" bXabXa \"");
	}

	// Test large replace indices
	{
		// Match 15 characters, one at a time
		ShouldCompile(__LINE__, regex, "(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)(.)");

		// Various replace patterns which reproduce the original
		JCharacter* patternList[] =
			{
			"$0",
			"$1$2$3$4$5$6$7$8$9$10$11$12$13$14$15$16",
			"$-17$-15$-14$-13$-12$-11$-10$-9$-8$-7$-6$-5$-4$-3$-2$-1",
			"$-16",
			NULL
			};

		const JCharacter* const buffer = "abcdefghijklmno"; // 15 characters
		JIndex i=0;
		while (patternList[i] != NULL)
			{
			JString thisBuffer = buffer;

			Assert(__LINE__, regex.SetReplacePattern(patternList[i]),
			                 "SetReplacePattern failed");

			regex.Match(thisBuffer, gMatchList);
			Assert(__LINE__, gMatchList->GetElementCount() == 16);

			JIndexRange newRange;
			regex.Replace(&thisBuffer, *gMatchList, &newRange);
			Assert(__LINE__, newRange.GetLength() == 15, "Matched wrong range");
			Assert(__LINE__, thisBuffer == buffer,
			       "Replaced string is \"" + thisBuffer + "\" instead of \"" + buffer + "\"");

			++i;
			}
	}

	// Test case-matching replacement
	{
		// Match a word
		ShouldCompile(__LINE__, regex, "[a-zA-Z0-9]+");

		const JCharacter* buffer = "  abc  ";

		// Without case-coercion
		const JCharacter* replacePattern = "XYZ";
		Assert(__LINE__, regex.SetReplacePattern(replacePattern), "SetReplacePattern failed");

		// Better match
		Assert(__LINE__, regex.Match(buffer, gMatchList), "Match failed");
		Assert(__LINE__, gMatchList->GetElement(1).Is(3, 5), "Located range incorrect");

		// Replace without case matching
		JString replacedString = regex.InterpolateMatches(buffer, *gMatchList);

		Assert(__LINE__, replacedString == "XYZ",
		       "Interpolation failed, actual string is \"" + replacedString + "\"");

// Replace with case matching

		// Force all characters to change
		regex.SetMatchCase();
		replacedString = regex.InterpolateMatches(buffer, *gMatchList);

		Assert(__LINE__, replacedString == "xyz",
		       "Interpolation failed, actual string is \"" + replacedString + "\"");



		// Change first character only (not any more)
		buffer = "  ABc  ";

		// Better match
		Assert(__LINE__, regex.Match(buffer, gMatchList), "Match failed");
		Assert(__LINE__, gMatchList->GetElement(1).Is(3, 5), "Located range incorrect");

		replacePattern = "xyz";
		Assert(__LINE__, regex.SetReplacePattern(replacePattern), "SetReplacePattern failed");

		regex.SetMatchCase();
		replacedString = regex.InterpolateMatches(buffer, *gMatchList);

		Assert(__LINE__, replacedString == "XYz",
		       "Interpolation failed, actual string is \"" + replacedString + "\"");



		// Change all again, but in opposite directions
		buffer = "  aBC  ";

		// Better match
		Assert(__LINE__, regex.Match(buffer, gMatchList), "Match failed");
		Assert(__LINE__, gMatchList->GetElement(1).Is(3, 5), "Located range incorrect");

		replacePattern = "Xyz";
		Assert(__LINE__, regex.SetReplacePattern(replacePattern), "SetReplacePattern failed");

		regex.SetMatchCase();
		replacedString = regex.InterpolateMatches(buffer, *gMatchList);

		Assert(__LINE__, replacedString == "xYZ",
		       "Interpolation failed, actual string is \"" + replacedString + "\"");
	}

	// Test case matching
	{
	}

// Test MatchBackward

	gString = "a23456bc90123d567efg12hi";
	ShouldCompile(__LINE__, regex, "[a-z]{1,", 5, 0); // Might as well test other stuff
	ShouldNotMatchBackward(__LINE__, regex, gString, 1);
	ShouldMatchBackward(__LINE__, regex, gString, 2, "a");
	ShouldMatchBackward(__LINE__, regex, gString, 7, "a");
	ShouldMatchBackward(__LINE__, regex, gString, 8, "b");
	ShouldMatchBackward(__LINE__, regex, gString, 9, "c");
	ShouldMatchBackward(__LINE__, regex, gString, 12, "c");
	ShouldMatchBackward(__LINE__, regex, gString, 20, "f");
	ShouldMatchBackward(__LINE__, regex, gString, 24, "h");
	ShouldMatchBackward(__LINE__, regex, gString, 25, "i");

// This sequence of calls caused a complicated bug at one time

	JRegex regex3;
	ShouldCompile(__LINE__, regex3, "a");
	ShouldNotCompile(__LINE__, regex3, "*");
	regex3.RestoreDefaults();

// Test compilation of a zero-length string

	ShouldNotCompile(__LINE__, regex, "");

// Test GetSubCount()'s recompilation
	// Null test; these won't cause a SubCount recompile
//	regex.RestoreDefaults(kTrue);
	regex.RestoreDefaults();
	ShouldCompile(__LINE__, regex, "a(b*)(c*)d");
	Assert(__LINE__, regex.GetSubCount() == 2, "Wrong number of subexpressions");
	regex.SetMatchOnly(kTrue);
	Assert(__LINE__, regex.GetSubCount() == 0, "Wrong number of subexpressions");
	regex.SetMatchOnly(kFalse);
	Assert(__LINE__, regex.GetSubCount() == 2, "Wrong number of subexpressions");

	regex.SetMatchOnly(kTrue);
	ShouldCompile(__LINE__, regex, "a(b*)d");
	regex.Match("abbd");
	Assert(__LINE__, regex.GetSubCount() == 0, "Wrong number of subexpressions");
	regex.SetMatchOnly(kFalse);
	// Recompilation triggered here
	Assert(__LINE__, regex.GetSubCount() == 1, "Wrong number of subexpressions");


// Test JCore Extensions

	// Testing word boundaries
	regex.RestoreDefaults();
	ShouldCompile(__LINE__, regex, "\\<(.*)\\>");

	gString = " abc  def  ";
	IntShouldBe(__LINE__, regex.MatchAll(gString, gMatchList), 1);
	Assert(__LINE__, gString.GetSubstring(gMatchList->GetElement(1)) == "abc  def");

	gString = "abc  def";
	IntShouldBe(__LINE__, regex.MatchAll(gString, gMatchList), 1);
	Assert(__LINE__, gString.GetSubstring(gMatchList->GetElement(1)) == "abc  def");



#if 0
	ShouldCompile(__LINE__, regex, "\\<");

	gString = " abc  def ";
	IntShouldBe(__LINE__, regex.MatchAll(gString, gMatchList), 2);
	Assert(__LINE__, gMatchList->GetElement(1).Is(2,1));
	Assert(__LINE__, gMatchList->GetElement(2).Is(7,6));
#endif

#if 0
	gString = "abc  def";
	IntShouldBe(__LINE__, regex.MatchAll(gString, gMatchList), 2);
	Assert(__LINE__, gMatchList->GetElement(1).Is(1,0));
	Assert(__LINE__, gMatchList->GetElement(2).Is(6,5));
#endif



#if 0
	ShouldCompile(__LINE__, regex, "\\>");

	gString = " abc  def ";
	IntShouldBe(__LINE__, regex.MatchAll(gString, gMatchList), 2);
	Assert(__LINE__, gMatchList->GetElement(1).Is(5,4));
	Assert(__LINE__, gMatchList->GetElement(2).Is(10,9));
cout << "Point 1" << endl;

	gString = "abc  def";
cout << "Point 2" << endl;
	IntShouldBe(__LINE__, regex.MatchAll(gString, gMatchList), 2);
cout << "Point 3" << endl;
	Assert(__LINE__, gMatchList->GetElement(1).Is(4,3));
	Assert(__LINE__, gMatchList->GetElement(2).Is(9,8));
#endif



#if 0
	// Word boundaries and \S
	ShouldCompile(__LINE__, regex, "\\<(\\S*)\\>");

	gString = " abc  def ";
	IntShouldBe(__LINE__, regex.MatchAll(gString, gMatchList), 2);
	Assert(__LINE__, gString.GetSubstring(gMatchList->GetElement(1)) == "abc");
	Assert(__LINE__, gString.GetSubstring(gMatchList->GetElement(2)) == "def");

	gString = "abc  def";
	IntShouldBe(__LINE__, regex.MatchAll(gString, gMatchList), 2);
	Assert(__LINE__, gString.GetSubstring(gMatchList->GetElement(1)) == "abc");
	Assert(__LINE__, gString.GetSubstring(gMatchList->GetElement(2)) == "def");
#endif

	cout << "Bug check complete.\n" << endl;

	cout << "Feature check\n" << endl;



// Who can use backreferences?
	regex.RestoreDefaults();
	ShouldSwitch(__LINE__, regex, JRegex::kBasic);
	Assert(__LINE__, regex.GetDialect() == JRegex::kBasic);

	cout << "Testing basic dialect backrefs" << endl;
	ShouldCompile(__LINE__, regex, "\\([bc]\\)\\1"); // Man page example
	ShouldMatch(__LINE__, regex, "bb", "bb");
	ShouldMatch(__LINE__, regex, "cc", "cc");
	ShouldNotMatch(__LINE__, regex, "bc");
	ShouldNotMatch(__LINE__, regex, "cb");
	ShouldNotMatch(__LINE__, regex, "b1");
	ShouldNotMatch(__LINE__, regex, "c1");

	ShouldCompile(__LINE__, regex, "\\(aa*\\)b\\1");
	ShouldMatch(__LINE__, regex, "aaabaaa", "aaabaaa");
	ShouldMatch(__LINE__, regex, "aaabaa", "aabaa");
	ShouldNotMatch(__LINE__, regex, "aaabbaa");
	ShouldNotMatch(__LINE__, regex, "aaabc");
	ShouldNotMatch(__LINE__, regex, "ab1");
	ShouldNotMatch(__LINE__, regex, "aaab1");
	cout << "If nothing failed, basic expressions have backreferences\n" << endl;

	cout << "Testing extended dialect backrefs" << endl;
	ShouldSwitch(__LINE__, regex, JRegex::kExtended);
	Assert(__LINE__, regex.GetDialect() == JRegex::kExtended);
	ShouldCompile(__LINE__, regex, "([bc])\\1"); // Man page example
	ShouldMatch(__LINE__, regex, "bb", "bb");
// These tests are not needed to show that ERE's don't have backref's, but can
// be added back in if Spencer ever fixes this.
#if 0
	ShouldMatch(__LINE__, regex, "cc", "cc");
	ShouldNotMatch(__LINE__, regex, "bc");
	ShouldNotMatch(__LINE__, regex, "cb");
	ShouldNotMatch(__LINE__, regex, "b1");
#endif
	ShouldNotMatch(__LINE__, regex, "c1");

#if 0
	ShouldCompile(__LINE__, regex, "(a+)b\\1");
	ShouldMatch(__LINE__, regex, "aaabaaa", "aaabaaa");
	ShouldMatch(__LINE__, regex, "aaabaa", "aabaa");
	ShouldNotMatch(__LINE__, regex, "aaabbaa");
	ShouldNotMatch(__LINE__, regex, "aaabc");
	ShouldNotMatch(__LINE__, regex, "ab1");
	ShouldNotMatch(__LINE__, regex, "aaab1");
#endif
	cout << "If nothing failed, extended expressions have backreferences\n" << endl;

	cout << "Feature check complete" << endl;

	delete gMatchList;

	return 0;
}

/******************************************************************************
 ShouldCompile

 *****************************************************************************/

void
ShouldCompile
	(
	const JSize       LINE,
	JRegex&           regex,
	const JCharacter* pattern
	)
{
	JError error = regex.SetPattern(pattern);
	if ( !error.OK() )
		{
		cout << "   Line " << LINE << ": pattern '" << pattern
		     << "' incorrectly failed to compile: " << error.GetType()
		     << ", " << error.GetMessage() << endl;
		}
	regex.GetPattern(&gPattern, &gLength); // Saving pointer to internal data, dangerous
	Assert(LINE, gPattern == regex.GetPattern() );
	Assert(LINE, strcmp(gPattern, pattern) == 0);
	Assert(LINE, regex.NULLCount() == 0);
}

/******************************************************************************
 ShouldNotCompile

 *****************************************************************************/

void
ShouldNotCompile
	(
	const JSize       LINE,
	JRegex&           regex,
	const JCharacter* pattern
	)
{
	if (regex.SetPattern(pattern).OK())
		{
		cout << "   Line " << LINE << ": pattern '" << pattern
		     << "' incorrectly compiled." << endl;
		}
	regex.GetPattern(&gPattern, &gLength); // Saving pointer to internal data, dangerous
	Assert(LINE, gPattern == regex.GetPattern() );
	Assert(LINE, regex.NULLCount() == 0);
	Assert(LINE, strcmp( pattern, gPattern ) == 0);
}

/******************************************************************************
 ShouldCompile

 *****************************************************************************/

void
ShouldCompile
	(
	const JSize       LINE,
	JRegex&           regex,
	const JCharacter* pattern,
	const JSize       length,
	const JSize       nullCount
	)
{
	if (!regex.SetPattern(pattern, length).OK())
		{
		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<length;i++)
			{
			cout << pattern[i];
			}
		cout << "' incorrectly failed to compile." << endl;
		}
	regex.GetPattern(&gPattern, &gLength); // Saving pointer to internal data, dangerous
	Assert(LINE, length == gLength);
	Assert(LINE, memcmp(gPattern, pattern, length) == 0);
	Assert(LINE, regex.NULLCount() == nullCount);
}

/******************************************************************************
 ShouldNotCompile

 *****************************************************************************/

void
ShouldNotCompile
	(
	const JSize       LINE,
	JRegex&           regex,
	const JCharacter* pattern,
	const JSize       length
	)
{
	if (regex.SetPattern(pattern).OK())
		{
		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<length;i++)
			{
			cout << pattern[i];
			}
		cout << "' incorrectly compiled." << endl;
		}
	regex.GetPattern(&gPattern, &gLength); // Saving pointer to internal data, dangerous
	Assert(LINE, length == gLength);
	Assert(LINE, memcmp(gPattern, pattern, length) == 0);
}

/******************************************************************************
 ShouldSwitch

 *****************************************************************************/

void
ShouldSwitch
	(
	const JSize           LINE,
	JRegex&               regex,
	const JRegex::Dialect dialect
	)
{
	if (!regex.SetDialect(dialect).OK())
		{
		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<gLength;i++)
			{
			cout << gPattern[i];
			}
		cout << "' incorrectly failed to switch dialects." << endl;
		}
	Assert(LINE, regex.GetDialect() == dialect);
}

/******************************************************************************
 ShouldNotSwitch

 *****************************************************************************/

void
ShouldNotSwitch
	(
	const JSize           LINE,
	JRegex&               regex,
	const JRegex::Dialect dialect
	)
{
	if (regex.SetDialect(dialect).OK())
		{
		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<gLength;i++)
			{
			cout << gPattern[i];
			}
		cout << "' incorrectly switched dialects." << endl;
		}

}

/******************************************************************************
 ShouldMatch

 *****************************************************************************/

void
ShouldMatch
	(
	const JSize       LINE,
	JRegex&           regex,
	const JCharacter* string,
	const JCharacter* compareString
	)
{
	gString = string;
	JIndexRange oldMatch = gMatch;

	if (!regex.Match(string, &gMatch))
//	if ((gMatch = regex.Match(string)).IsNothing())
		{
		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<gLength;i++)
			{
			cout << gPattern[i];
			}
		 cout << "' incorrectly failed to match '" << compareString << "' in '"
		      << string << "'" << endl;
//*		Assert(LINE, gMatch == oldMatch, "match failed but parameter was changed");
		return;
		}
	else
		{
		MatchShouldBe(LINE, compareString);
		}

	if (!regex.Match(string))
		{
		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<gLength;i++)
			{
			cout << gPattern[i];
			}
		cout << "' incorrectly failed to match in '"
		     << string << "'" << endl;
		}

	// Now test for equivalence to special cases of the other forms
}

/******************************************************************************
 ShouldNotMatch

 *****************************************************************************/

void
ShouldNotMatch
	(
	const JSize       LINE,
	JRegex&           regex,
	const JCharacter* string
	)
{
	gString = string;
	JIndexRange oldMatch = gMatch;

	if (regex.Match(string, &gMatch))
//	if (!(gMatch = regex.Match(string)).IsNothing())
		{
		JString matchedString = gString.GetSubstring(gMatch);

		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<gLength;i++)
			{
			cout << gPattern[i];
			}
		cout << "' incorrectly matched '" << matchedString << "' in '"
		     << gString << "'" << endl;
		return;
		}
	else
		{
//*		Assert(LINE, gMatch == oldMatch, "Match failed but parameter was changed");
		}

	if (regex.Match(string))
		{
		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<gLength;i++)
			{
			cout << gPattern[i];
			}
		cout << "' incorrectly matched in '" << gString
	    	 << "'" << endl;
		}
}

/******************************************************************************
 MatchShouldBe

 *****************************************************************************/

void
MatchShouldBe
	(
	const JSize       LINE,
	const JCharacter* compareString
	)
{
	JString matchedString = gString.GetSubstring(gMatch);

	if (matchedString != compareString)
		{
		cout << "   Pattern '";
		for (JIndex i=0;i<gLength;i++)
			{
			cout << gPattern[i];
			}
		cout << "' matching on '" << gString <<"' matched '"
		     << matchedString << "' != '" << compareString << "'" << endl;
		}
}

/******************************************************************************
 IntShouldBe

 *****************************************************************************/

void
IntShouldBe
	(
	const JSize    LINE,
	const JInteger anInt,
	const JInteger expecting
	)
{
	if ( anInt != expecting)
		{
		cout << "   Line " << LINE << ": blast, wrong offset: " << anInt
		     << ", expecting: " << expecting << endl;
		}
}

/******************************************************************************
 Assert

 *****************************************************************************/

void
Assert
	(
	const JSize       LINE,
	const int         test
	)
{
	if (!test)
		{
		cout << "   Line " << LINE << ": Blarg, test failed" << endl;
		}
}

/******************************************************************************
 Assert

 *****************************************************************************/

void
Assert
	(
	const JSize       LINE,
	const int         test,
	const JCharacter* description
	)
{
	if (!test)
		{
		cout << "   Line " << LINE << ": " << description << endl;
		}
}

/******************************************************************************
 ShouldMatchFrom

 *****************************************************************************/

void
ShouldMatchFrom
	(
	const JSize       LINE,
	JRegex&           regex,
	const JCharacter* string,
	const JSize       offset,
	const JCharacter* compareString
	)
{
	gString = string;
	JIndexRange oldMatch = gMatch;

	if (!regex.MatchFrom(string, offset, &gMatch))
		{
		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<gLength;i++)
			{
			cout << gPattern[i];
			}
		cout << "' incorrectly failed to match in '"
		     << gString <<  "' starting at position " << offset << endl;
		Assert(LINE, gMatch == oldMatch, "Match failed but parameter was changed");
		return;
		}
	else
		{
		MatchShouldBe(LINE, compareString);
		}

	if (!regex.MatchFrom(string, offset))
		{
		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<gLength;i++)
			{
			cout << gPattern[i];
			}
		cout << "' incorrectly failed to match in '"
		     << gString << "' starting at position " << offset << endl;
		}
}

/******************************************************************************
 ShouldNotMatchFrom

 *****************************************************************************/

void
ShouldNotMatchFrom
	(
	const JSize       LINE,
	JRegex&           regex,
	const JCharacter* string,
	const JSize       offset
	)
{
	gString = string;
	JIndexRange oldMatch = gMatch;

	if (regex.MatchFrom(string, offset, &gMatch))
		{
		JString matchedString = gString.GetSubstring(gMatch);

		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<gLength;i++)
			{
			cout << gPattern[i];
			}
		cout << "' incorrectly matched '" << matchedString
		     << "' in '" << gString << "' starting at position " << offset << endl;
		return;
		}
	else
		{
		Assert(LINE, gMatch == oldMatch, "Match failed but parameter was changed");
		}

	if (regex.MatchFrom(string, offset))
		{
		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<gLength;i++)
			{
			cout << gPattern[i];
			}
		cout << "' incorrectly matched in '"
		     << gString << "' starting at position " << offset << endl;
		}
}

/******************************************************************************
 ShouldMatchAfter

 *****************************************************************************/

void
ShouldMatchAfter
	(
	const JSize         LINE,
	JRegex&             regex,
	const JCharacter*   string,
	const JIndexRange& startAfter,
	const JCharacter*   compareString
	)
{
	gString = string;
	JIndexRange oldMatch = gMatch;
	JIndexRange copy = startAfter;

	if (!regex.MatchAfter(string, startAfter, &gMatch))
		{
		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<gLength;i++)
			{
			cout << gPattern[i];
			}
		cout << "' incorrectly failed to match in '"
		     << gString <<  "' after (" << copy << ")" << endl;
		Assert(LINE, gMatch == oldMatch, "Match failed but parameter was changed");
		return;
		}
	else
		{
		MatchShouldBe(LINE, compareString);
		}

	if (!regex.MatchAfter(string, startAfter))
		{
		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<gLength;i++)
			{
			cout << gPattern[i];
			}
		cout << "' incorrectly failed to match in '"
		     << gString << "' after (" << copy << ")" << endl;
		}
}

/******************************************************************************
 ShouldNotMatchAfter

 *****************************************************************************/

void
ShouldNotMatchAfter
	(
	const JSize         LINE,
	JRegex&             regex,
	const JCharacter*   string,
	const JIndexRange& startAfter
	)
{
	gString = string;
	JIndexRange oldMatch = gMatch;
	JIndexRange copy = startAfter;
	if (regex.MatchAfter(string, startAfter, &gMatch))
		{
		JString matchedString = gString.GetSubstring(gMatch);

		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<gLength;i++)
			{
			cout << gPattern[i];
			}
		cout << "' incorrectly matched '" << matchedString
		     << "' in '" << gString <<  "' after (" << copy << ")" << endl;
		return;
		}
	else 
		{
		Assert(LINE, gMatch == oldMatch, "Match failed but parameter was changed");
		}

	if (regex.MatchAfter(string, startAfter))
		{
		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<gLength;i++)
			{
			cout << gPattern[i];
			}
		cout << "' incorrectly matched in '"
		     << gString << "' after (" << copy << ")" << endl;
		return;
		}

//	ShouldNotMatchWithin
}

/******************************************************************************
 ShouldMatchWithin

 *****************************************************************************/

void
ShouldMatchWithin
	(
	const JSize         LINE,
	JRegex&             regex,
	const JCharacter*   string,
	const JIndexRange& range,
	const JCharacter*   compareString
	)
{
	gString = string;
	JIndexRange oldMatch = gMatch;
	if (!regex.MatchWithin(string, range, &gMatch))
		{
		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<gLength;i++)
			{
			cout << gPattern[i];
			}
		cout << "' incorrectly failed to match in '"
		     << gString <<  "' within (" << range << ")" << endl;
		Assert(LINE, gMatch == oldMatch, "Match failed but parameter was changed");
		return;
		}
	else
		{
		MatchShouldBe(LINE, compareString);
		}

	if (!regex.MatchWithin(string, range))
		{
		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<gLength;i++)
			{
			cout << gPattern[i];
			}
		cout << "' incorrectly failed to match in '"
		     << gString << "' within (" << range << ")" << endl;
		}
}

/******************************************************************************
 ShouldNotMatchWithin

 *****************************************************************************/

void
ShouldNotMatchWithin
	(
	const JSize         LINE,
	JRegex&             regex,
	const JCharacter*   string,
	const JIndexRange& range
	)
{
	gString = string;
	JIndexRange oldMatch = gMatch;
	if (regex.MatchWithin(string, range, &gMatch))
		{
		JString matchedString = gString.GetSubstring(gMatch);

		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<gLength;i++)
			{
			cout << gPattern[i];
			}
		cout << "' incorrectly matched '" << matchedString
		     << "' in '" << gString <<  "' within (" << range << ")" << endl;
		return;
		}
	else 
		{
		Assert(LINE, gMatch == oldMatch, "Match failed but parameter was changed");
		}

	if (regex.MatchWithin(string, range))
		{
		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<gLength;i++)
			{
			cout << gPattern[i];
			}
		cout << "' incorrectly matched in '"
		     << gString << "' within (" << range << ")" << endl;
		}
}

/******************************************************************************
 ShouldMatchLastWithin

 *****************************************************************************/

void
ShouldMatchLastWithin
	(
	const JSize         LINE,
	JRegex&             regex,
	const JCharacter*   string,
	const JIndexRange& range,
	const JCharacter*   compareString,
	const JSize         matchCount
	)
{
	gString = string;
	JIndexRange oldMatch = gMatch;
	JSize count = regex.MatchLastWithin(string, range, &gMatch);
	if (count == 0)
		{
		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<gLength;i++)
			{
			cout << gPattern[i];
			}
		cout << "' incorrectly failed to match in '"
		     << gString <<  "' within (" << range << ")" << endl;
		Assert(LINE, gMatch == oldMatch, "Match failed but parameter was changed");
		}
	else
		{
		MatchShouldBe(LINE, compareString);
		IntShouldBe(LINE, count, matchCount);
		}
}

/******************************************************************************
 ShouldNotMatchLastWithin

 *****************************************************************************/

void
ShouldNotMatchLastWithin
	(
	const JSize         LINE,
	JRegex&             regex,
	const JCharacter*   string,
	const JIndexRange& range
	)
{
	gString = string;
	JIndexRange oldMatch = gMatch;
	JSize count = regex.MatchLastWithin(string, range, &gMatch);
	if (count != 0)
		{
		JString matchedString = gString.GetSubstring(gMatch);

		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<gLength;i++)
			{
			cout << gPattern[i];
			}
		cout << "' incorrectly matched '" << matchedString << "' in '" << gString
		<<  "' within (" << range << "), count was " << count << endl;
		return;
		}
	else 
		{
		Assert(LINE, gMatch == oldMatch, "Match failed but parameter was changed");
		}

}

/******************************************************************************
 ShouldMatchBackward

 *****************************************************************************/

void
ShouldMatchBackward
	(
	const JSize       LINE,
	JRegex&           regex,
	const JCharacter* string,
	const JSize       offset,
	const JCharacter* compareString
	)
{
	gString = string;
	JIndexRange oldMatch = gMatch;

	if (!regex.MatchBackward(string, offset, &gMatch))
		{
		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<gLength;i++)
			{
			cout << gPattern[i];
			}
		cout << "' incorrectly failed to match backward in '"
		     << gString <<  "' starting at position " << offset << endl;
		Assert(LINE, gMatch == oldMatch, "Match failed but parameter was changed");
		}
	else
		{
		MatchShouldBe(LINE, compareString);
		}
}

/******************************************************************************
 ShouldNotMatchBackward

 *****************************************************************************/

void
ShouldNotMatchBackward
	(
	const JSize       LINE,
	JRegex&           regex,
	const JCharacter* string,
	const JSize       offset
	)
{
	gString = string;
	JIndexRange oldMatch = gMatch;

	if ( regex.MatchBackward(string, offset, &gMatch) )
		{
		JString matchedString = gString.GetSubstring(gMatch);

		cout << "   Line " << LINE << ": pattern '";
		for (JIndex i=0;i<gLength;i++)
			{
			cout << gPattern[i];
			}
		cout << "' incorrectly matched '" << matchedString
		     << "' backwards in '" << gString << "' starting at position " << offset << endl;
		}
	else
		{
		Assert(LINE, gMatch == oldMatch, "Match failed but parameter was changed");
		}
}
