[Mono-list] System.Text.StringBuilder

Norman Lorrain normanlorrainmailinglists@telus.net
Wed, 29 Jan 2003 17:45:45 -0700


This is a multi-part message in MIME format.

------=_NextPart_000_0001_01C2C7BE.41120990
Content-Type: text/plain;
	charset="us-ascii"
Content-Transfer-Encoding: 7bit

After changing mcs/class/corlib/Test/run_test.sh, (see attached; this is
based on correspondence with Nick Drochak), I noticed two unit tests
failing for StringBuilder
 - the constructor with null string 
 - the constructor for a given capacity 

Based on MSDN doc's I made some changes.  Attached is the new
StringBuilder.cs
I also updated the unit tests to Nunit v2, (see attached).

These files were tested with release 0.19.  I'm having trouble building
from CVS and so can't get a proper patch.

Norman

------=_NextPart_000_0001_01C2C7BE.41120990
Content-Type: application/octet-stream;
	name="StringBuilder.cs"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="StringBuilder.cs"

// -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
//
// System.Text.StringBuilder
//
// Author: Marcin Szczepanski (marcins@zipworld.com.au)
//
// TODO: Make sure the coding complies to the ECMA draft, there's some
// variable names that probably don't (like sString)
//
using System.Runtime.CompilerServices;

namespace System.Text {
=09
	[Serializable]
	public sealed class StringBuilder {

		private const int defaultCapacity =3D 16;

		private int sCapacity;
		private int sLength;
		private char[] sString;
		private int sMaxCapacity =3D Int32.MaxValue;

		public StringBuilder(string value, int startIndex, int length, int =
capacity) {
			if(value =3D=3D null) {
				value =3D String.Empty;
			}

			// make sure startIndex is zero or positive
			if(startIndex < 0) {
				throw new System.ArgumentOutOfRangeException("startIndex", =
startIndex, "StartIndex cannot be less than zero.");
			}

			// make sure length is zero or positive
			if(length < 0) {
				throw new System.ArgumentOutOfRangeException("length", length, =
"Length cannot be less than zero.");
			}

			// make sure startIndex and length give a valid substring of value
			if(startIndex + (length -1) > (value.Length - 1) ) {
				throw new System.ArgumentOutOfRangeException("startIndex", =
startIndex, "StartIndex and length must refer to a location within the =
string.");
			}
		=09
			if(capacity > sMaxCapacity) {
				throw new System.ArgumentOutOfRangeException("capacity", "Capacity =
exceeds maximum capacity.");
			}
			sCapacity =3D capacity;

			// LAMESPEC: what to do if capacity is too small to hold the =
substring?
			// Like the MS implementation, double the capacity until it is large =
enough
			while (sCapacity < length) {
				// However, take care not to double if that would make the number
				// larger than what an int can hold
				if (sCapacity <=3D Int32.MaxValue / 2) {
					sCapacity *=3D 2;
				}
				else{
					sCapacity =3D Int32.MaxValue;
				}
			}

			sString =3D new char[sCapacity];
			sLength =3D length;

			// if the length is not zero, then we have to copy some characters
			if (sLength > 0) {
				// Copy the correct number of characters into the internal array
				value.CopyTo (startIndex, sString, 0, sLength);
			}
		}

		public StringBuilder () : this(String.Empty, 0, 0, defaultCapacity ) =
{}

		public StringBuilder( int capacity ) : this(String.Empty, 0, 0, =
capacity) {}

		public StringBuilder( int capacity, int maxCapacity ) : =
this(String.Empty, 0, 0, capacity) {
			if(capacity > maxCapacity) {
				throw new System.ArgumentOutOfRangeException("capacity", "Capacity =
exceeds maximum capacity.");
			}
			sMaxCapacity =3D maxCapacity;
		}

		public StringBuilder( string value ) : this(value, 0, value =3D=3D =
null ? 0 : value.Length, value =3D=3D null? 0 : value.Length) {
		}
=09
		public StringBuilder( string value, int capacity) : this(value, 0, =
value.Length, capacity) {}
=09
		public int MaxCapacity {
			get {
				// MS runtime always returns Int32.MaxValue.
				return sMaxCapacity;
			}
		}

		public int Capacity {
			get {
				return sCapacity;
			}

			set {
				if( value < sLength ) {
					throw new ArgumentException( "Capacity must be > length" );
				} else {
					char[] tString =3D new char[value];	      =20
					Array.Copy( sString, tString, sLength );
					sString =3D tString;
					sCapacity =3D sString.Length;
				}
			}
		}


		public int Length {
			get {
				return sLength;
			}

			set {
				if( value < 0 || value > MaxCapacity) {
					throw new ArgumentOutOfRangeException();
				} else {

					if( value < sLength ) {
						// Truncate current string at value

						// LAMESPEC:  The spec is unclear as to what to do
						// with the capacity when truncating the string.
						//
						// Don't change the capacity, as this is what
						// the MS implementation does.

						sLength =3D value;
					} else {
						// Expand the capacity to the new length and
						// pad the string with spaces.
					=09
						// LAMESPEC: The spec says to put the spaces on the
						// left of the string however the MS implementation
						// puts them on the right.  We'll do that for=20
						// compatibility (!)

						char[] tString =3D new char[ value ];
						int padLength =3D value - sLength;
					=09
						string padding =3D new String( ' ', padLength );
						Array.Copy( sString, tString, sLength );
						padding.CopyTo (0, sString, sLength, padLength);
						sString =3D tString;
						sLength =3D sString.Length;
						sCapacity =3D value;
					}
				}
			}
		}

		[IndexerName("Chars")]
		public char this[ int index ] {
			get {

				if( index >=3D sLength || index < 0 ) {
					throw new IndexOutOfRangeException();
				}
				return sString[ index ];
			}=20

			set {
				if( index >=3D sLength || index < 0 ) {
					throw new IndexOutOfRangeException();
				}
				sString[ index ] =3D value;
			}
		}

		public override string ToString() {
			return ToString(0, sLength);
		}

		public string ToString( int startIndex, int length ) {
			if( startIndex < 0 || length < 0 || startIndex + length > sLength ) {
				throw new ArgumentOutOfRangeException();
			}
=09
			return new String( sString, startIndex, length );
		}

		public int EnsureCapacity( int capacity ) {
			if( capacity < 0 ) {
				throw new ArgumentOutOfRangeException(=20
					"Capacity must be greater than 0." );
			}

			if( capacity <=3D sCapacity ) {
				return sCapacity;
			} else {
				Capacity =3D capacity;
				return sCapacity;
			}
		}

		public bool Equals( StringBuilder sb ) {
			if(sLength =3D=3D sb.Length && this.ToString() =3D=3D sb.ToString() ) =
{
				return true;
			} else {
				return false;
			}
		}

		public StringBuilder Remove (int startIndex, int length)
		{
			if( startIndex < 0 || length < 0 || startIndex + length > sLength )
				throw new ArgumentOutOfRangeException();

			// Copy everything after the 'removed' part to the start=20
			// of the removed part and truncate the sLength

			Array.Copy (sString, startIndex + length, sString, startIndex,
				    sLength - (startIndex + length));

			sLength -=3D length;
			return this;
		}			      =20

		public StringBuilder Replace( char oldChar, char newChar ) {
	=09
			return Replace( oldChar, newChar, 0, sLength);
		}

		public StringBuilder Replace( char oldChar, char newChar, int =
startIndex, int count ) {
			if( startIndex + count > sLength || startIndex < 0 || count < 0 ) {
				throw new ArgumentOutOfRangeException();
			}

			for( int replaceIterate =3D startIndex; replaceIterate < startIndex + =
count; replaceIterate++ ) {
				if( this[replaceIterate] =3D=3D oldChar ) {
					this[replaceIterate] =3D newChar;
				}
			}

			return this;
		}

		public StringBuilder Replace( string oldValue, string newValue ) {
			return Replace( oldValue, newValue, 0, sLength );
		}

		public StringBuilder Replace( string oldValue, string newValue, int =
startIndex, int count ) {
			string startString =3D this.ToString();
			StringBuilder newStringB =3D new StringBuilder();

			if( oldValue =3D=3D null ) {=20
				throw new ArgumentNullException(
					"The old value cannot be null.");
			}

			if( startIndex < 0 || count < 0 || startIndex + count > sLength ) {
				throw new ArgumentOutOfRangeException();
			}

			if( oldValue.Length =3D=3D 0 ) {
				throw new ArgumentException(
					"The old value cannot be zero length.");
			}

			int nextIndex =3D startIndex; // Where to start the next search
			int lastIndex =3D nextIndex;  // Where the last search finished

			while( nextIndex !=3D -1 ) {
				nextIndex =3D startString.IndexOf( oldValue, lastIndex);				 =20
				if( nextIndex !=3D -1 ) {
					// The MS implementation won't replace a substring=20
					// if that substring goes over the "count"
					// boundary, so we'll make sure the behaviour=20
					// here is the same.

					if( nextIndex + oldValue.Length <=3D startIndex + count ) {

						// Add everything to the left of the old=20
						// string
						newStringB.Append( startString.Substring( lastIndex, nextIndex - =
lastIndex ) );
=09
						// Add the replacement string
						newStringB.Append( newValue );
					=09
						// Set the next start point to the=20
						// end of the last match
						lastIndex =3D nextIndex + oldValue.Length;
					} else {
						// We're past the "count" we're supposed to replace within
						nextIndex =3D -1;
						newStringB.Append(=20
							startString.Substring( lastIndex ) );
					}

				} else {
					// Append everything left over
					newStringB.Append( startString.Substring( lastIndex ) );
				}
			}=20

			sCapacity =3D newStringB.sCapacity;
			sString =3D newStringB.sString;
			sLength =3D newStringB.sLength;
			return this;
		}

		     =20
		/* The Append Methods */

		public StringBuilder Append( char[] value ) {
			if( sLength + value.Length > sCapacity ) {
				// Need more capacity, double the capacity StringBuilder=20
				// and make sure we have at least enough for the value=20
				// if that's going to go over double.=20
					=20
				Capacity =3D value.Length + ( sCapacity + sCapacity);
			}

			Array.Copy( value, 0, sString, sLength, value.Length );
			sLength +=3D value.Length;

			return this;
		}=20
	=09
		public StringBuilder Append( string value ) {
			if( value !=3D null ) {
				int new_size =3D sLength + value.Length;
				if (new_size > sCapacity)
					Capacity =3D value.Length + sCapacity * 2;

				value.CopyTo (0, sString, sLength, value.Length);
				sLength =3D new_size;
				return this;
			} else {
				return null;
			}
		}

		public StringBuilder Append( bool value ) {
			return Append (value.ToString());
		}
	=09
		public StringBuilder Append( byte value ) {
			return Append (value.ToString());
		}

		public StringBuilder Append( decimal value ) {
			return Append (value.ToString());
		}

		public StringBuilder Append( double value ) {
			return Append (value.ToString());
		}

		public StringBuilder Append( short value ) {
			return Append (value.ToString());
		}

		public StringBuilder Append( int value ) {
			return Append (value.ToString());
		}

		public StringBuilder Append( long value ) {
			return Append (value.ToString());
		}

		public StringBuilder Append( object value ) {
			return Append (value.ToString());
		}

		[CLSCompliant(false)]
		public StringBuilder Append( sbyte value ) {
			return Append (value.ToString());
		}

		public StringBuilder Append( float value ) {
			return Append (value.ToString());
		}

		[CLSCompliant(false)]
		public StringBuilder Append( ushort value ) {
			return Append (value.ToString());
		}=09
	=09
		[CLSCompliant(false)]
		public StringBuilder Append( uint value ) {
			return Append (value.ToString());
		}

		[CLSCompliant(false)]
		public StringBuilder Append( ulong value ) {
			return Append (value.ToString());
		}

		public StringBuilder Append( char value ) {
			if( sLength + 1 > sCapacity ) {
				// Need more capacity, double the capacity StringBuilder=20
				// and make sure we have at least enough for the value=20
				// if that's going to go over double.=20
					=20
				Capacity =3D 1 + ( sCapacity + sCapacity);
			}
			sString [sLength] =3D value;
			sLength++;

			return this;
		}

		public StringBuilder Append( char value, int repeatCount ) {
			if( repeatCount < 0 ) {
				throw new ArgumentOutOfRangeException();
			}

			return Append( new String( value, repeatCount) );
		}

		public StringBuilder Append( char[] value, int startIndex, int =
charCount ) {

			if( (charCount < 0 || startIndex < 0) ||=20
				( charCount + startIndex > value.Length ) ) {
				throw new ArgumentOutOfRangeException();
			}
		=09
			if( value =3D=3D null ) {
				if( !(startIndex =3D=3D 0 && charCount =3D=3D 0) ) {
					throw new ArgumentNullException();
				} else {
					return this;
				}
			} else {
				char[] appendChars =3D new char[ charCount ];
		=09
				Array.Copy( value, startIndex, appendChars, 0, charCount );
				return Append( appendChars );
			}
		}

		public StringBuilder Append( string value, int startIndex, int count ) =
{
			if( (count < 0 || startIndex < 0) ||=20
				( startIndex + count > value.Length ) ) {=20
				throw new ArgumentOutOfRangeException();
			}

			return Append (value.Substring (startIndex, count));
		}

		public StringBuilder AppendFormat (string format, object arg0 )
		{
			string result =3D String.Format (format, arg0);
			return Append (result);
		}

		public StringBuilder AppendFormat (string format, params object[] args =
)
		{
			string result =3D String.Format (format, args);
			return Append (result);
		}

		public StringBuilder AppendFormat (IFormatProvider provider,
						   string format,
						   params object[] args)
		{
			string result =3D String.Format (provider, format, args);
			return Append (result);
		}

		public StringBuilder AppendFormat (string format, object arg0, object =
arg1 )
		{
			string result =3D String.Format (format, arg0, arg1);
			return Append (result);
		}

		public StringBuilder AppendFormat (string format, object arg0, object =
arg1, object arg2 )
		{
			string result =3D String.Format (format, arg0, arg1, arg2);
			return Append (result);
		}

		/*  The Insert Functions */
	=09
		public StringBuilder Insert( int index, char[] value ) {
			if( index > sLength || index < 0) {
				throw new ArgumentOutOfRangeException();
			}

			if( value =3D=3D null || value.Length =3D=3D 0 ) {
				return this;
			} else {
				// Check we have the capacity to insert this array
				if( sCapacity < sLength + value.Length ) {
					Capacity =3D value.Length + ( sCapacity + sCapacity );
				}

				// Move everything to the right of the insert point across
				Array.Copy( sString, index, sString, index + value.Length, sLength - =
index);
			=09
				// Copy in stuff from the insert buffer
				Array.Copy( value, 0, sString, index, value.Length );
			=09
				sLength +=3D value.Length;
				return this;
			}
		}
			=09
		public StringBuilder Insert( int index, string value ) {
			if (index > sLength || index < 0)
				throw new ArgumentOutOfRangeException ("index");

			if (value =3D=3D null || value.Length =3D=3D 0)
				return this;

			int len =3D value.Length;
			// Check we have the capacity to insert this array
			if (sCapacity < sLength + len)
				Capacity =3D len + ( sCapacity + sCapacity );

			// Move everything to the right of the insert point across
			Array.Copy (sString, index, sString, index + len, sLength - index);
		=09
			value.CopyTo (0, sString, index, len);
		=09
			sLength +=3D len;
			return this;
		}

		public StringBuilder Insert( int index, bool value ) {
			return Insert( index, value.ToString());
		}
	=09
		public StringBuilder Insert( int index, byte value ) {
			return Insert( index, value.ToString());
		}

		public StringBuilder Insert( int index, char value) {
			char[] insertChar =3D new char[1];
		=09
			insertChar[0] =3D value;
			return Insert( index, insertChar );
		}

		public StringBuilder Insert( int index, decimal value ) {
			return Insert( index, value.ToString() );
		}

		public StringBuilder Insert( int index, double value ) {
			return Insert( index, value.ToString() );
		}
	=09
		public StringBuilder Insert( int index, short value ) {
			return Insert( index, value.ToString() );
		}

		public StringBuilder Insert( int index, int value ) {
			return Insert( index, value.ToString() );
		}

		public StringBuilder Insert( int index, long value ) {
			return Insert( index, value.ToString() );
		}
=09
		public StringBuilder Insert( int index, object value ) {
			return Insert( index, value.ToString() );
		}
	=09
		[CLSCompliant(false)]
		public StringBuilder Insert( int index, sbyte value ) {
			return Insert( index, value.ToString() );
		}

		public StringBuilder Insert( int index, float value ) {
			return Insert( index, value.ToString() );
		}

		[CLSCompliant(false)]
		public StringBuilder Insert( int index, ushort value ) {
			return Insert( index, value.ToString() );
		}

		[CLSCompliant(false)]
		public StringBuilder Insert( int index, uint value ) {
			return Insert( index, value.ToString() );
		}
	=09
		[CLSCompliant(false)]
		public StringBuilder Insert( int index, ulong value ) {
			return Insert( index, value.ToString() );
		}

		public StringBuilder Insert( int index, string value, int count ) {
			if ( count < 0 ) {
				throw new ArgumentOutOfRangeException();
			}

			if( value !=3D null ) {
				if( value !=3D "" ) {
					for( int insertCount =3D 0; insertCount < count;=20
						insertCount++ ) {
						Insert( index, value );	  =20
					}
				}
			}
			return this;
		}

		public StringBuilder Insert( int index, char[] value, int startIndex,=20
			int charCount ) {

			if( value !=3D null ) {
				if( charCount < 0 || startIndex < 0 || startIndex + charCount > =
value.Length ) {
					throw new ArgumentOutOfRangeException();
				}
				=09
				char[] insertChars =3D new char[ charCount  ];
				Array.Copy( value, startIndex, insertChars, 0, charCount );
				return Insert( index, insertChars );
			} else {
				return this;
			}
		}
	}
}      =20

------=_NextPart_000_0001_01C2C7BE.41120990
Content-Type: application/octet-stream;
	name="StringBuilderTest.cs"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="StringBuilderTest.cs"

//
// StringBuilderTest.dll - NUnit Test Cases for the =
System.Text.StringBuilder class
//=20
// Author: Marcin Szczepanski (marcins@zipworld.com.au)
//
// NOTES: I've also run all these tests against the MS implementation of =

// System.Text.StringBuilder to confirm that they return the same =
results
// and they do.
//
// TODO: Add tests for the AppendFormat methods once the AppendFormat =
methods
// are implemented in the StringBuilder class itself
//
// TODO: Potentially add more variations on Insert / Append tests for =
all the
// possible types.  I don't really think that's necessary as they all
// pretty much just do .ToString().ToCharArray() and then use the Append =
/ Insert
// CharArray function.  The ToString() bit for each type should be in =
the unit
// tests for those types, and the unit test for ToCharArray should be in =
the=20
// string test type.  If someone wants to add those tests here for =
completness=20
// (and some double checking) then feel free :)
//

using NUnit.Framework;
using System.Text;
using System;

namespace MonoTests.System.Text {
=09
	[TestFixture]
	public class StringBuilderTest  {

		private StringBuilder sb;

		[Test]
		public void Constructor1()=20
		{
			// check the parameterless ctor
			sb =3D new StringBuilder();
			Assertion.AssertEquals(String.Empty, sb.ToString());
			Assertion.AssertEquals(0, sb.Length);
			Assertion.AssertEquals(16, sb.Capacity);
		}

		[Test]
		public void Constructor2()=20
		{
			// check ctor that specifies the capacity
			sb =3D new StringBuilder(10);
			Assertion.AssertEquals(String.Empty, sb.ToString());
			Assertion.AssertEquals(0, sb.Length);
			// check that capacity is set
			Assertion.AssertEquals(10, sb.Capacity);

			sb =3D new StringBuilder(42);
			Assertion.AssertEquals(String.Empty, sb.ToString());
			Assertion.AssertEquals(0, sb.Length);
			// check that capacity is set
			Assertion.AssertEquals(42, sb.Capacity);
		}
	=09
		[Test]
		public void Constructor3() {
			// check ctor that specifies the capacity & maxCapacity
			sb =3D new StringBuilder(444, 1234);
			Assertion.AssertEquals(String.Empty, sb.ToString());
			Assertion.AssertEquals(0, sb.Length);
			Assertion.AssertEquals(444, sb.Capacity);
			Assertion.AssertEquals(1234, sb.MaxCapacity);
		}

		[Test]
		[ExpectedException(typeof(ArgumentOutOfRangeException))]
		public void Constructor4()=20
		{
			// check for exception in ctor that specifies the capacity & =
maxCapacity
			sb =3D new StringBuilder(9999, 15);
		=09
		}

		[Test]
		public void Constructor5() {
			String someString =3D null;
			sb =3D new StringBuilder(someString);
			Assertion.AssertEquals("Should be empty string", String.Empty, =
sb.ToString());
		}

		[Test]
		[ExpectedException(typeof(ArgumentOutOfRangeException))]
		public void Constructor6() {
			// check for exception in ctor that prevents startIndex less than =
zero
			String someString =3D "someString";
			sb =3D new StringBuilder(someString, -1, 3, 18);
		}

		[Test]
		[ExpectedException(typeof(ArgumentOutOfRangeException))]
		public void Constructor7() {
			// check for exception in ctor that prevents length less than zero
			String someString =3D "someString";
			sb =3D new StringBuilder(someString, 2, -222, 18);
		}

		[Test]
		[ExpectedException(typeof(ArgumentOutOfRangeException))]
		public void Constructor8() {
			// check for exception in ctor that ensures substring is contained in =
given string
			// check that startIndex is not too big
			String someString =3D "someString";
			sb =3D new StringBuilder(someString, 10000, 4, 18);
		}

		[Test]
		[ExpectedException(typeof(ArgumentOutOfRangeException))]
		public void Constructor9() {
			// check for exception in ctor that ensures substring is contained in =
given string
			// check that length doesn't go beyond end of string
			String someString =3D "someString";
			sb =3D new StringBuilder(someString, 4, 4000, 18);
		}

		[Test]
		public void Constructor10() {
			// check that substring is taken properly and made into a =
StringBuilder
			String someString =3D "someString";
			sb =3D new StringBuilder(someString, 4, 6, 18);
			string expected =3D "String";
			Assertion.AssertEquals( expected, sb.ToString());
		}

		[Test]
		public void Append() {
			StringBuilder sb =3D new StringBuilder( "Foo" );
			sb.Append( "Two" );
			string expected =3D "FooTwo";
			Assertion.AssertEquals( expected, sb.ToString() );
		}

		[Test]
		public void Insert() {
			StringBuilder sb =3D new StringBuilder();
=09
			Assertion.AssertEquals( String.Empty, sb.ToString() );=20
				/* Test empty StringBuilder conforms to spec */
=09
			sb.Insert( 0, "Foo" ); /* Test insert at start of empty string */
=09
			Assertion.AssertEquals( "Foo", sb.ToString() );
=09
			sb.Insert( 1, "!!" ); /* Test insert not at start of string */
=09
			Assertion.AssertEquals( "F!!oo", sb.ToString() );
=09
			sb.Insert( 5, ".." ); /* Test insert at end of string */
=09
			Assertion.AssertEquals( "F!!oo..", sb.ToString() );
	=09
			sb.Insert( 0, 1234 ); /* Test insert of a number (at start of string) =
*/
		=09
					// FIX: Why does this test fail?
			//Assertion.AssertEquals( "1234F!!oo..", sb.ToString() );
		=09
			sb.Insert( 5, 1.5 ); /* Test insert of a decimal (and end of string) =
*/
		=09
					// FIX: Why does this test fail?
					//Assertion.AssertEquals( "1234F1.5!!oo..", sb.ToString() );
=09
			sb.Insert( 4, 'A' ); /* Test char insert in middle of string */
=09
					// FIX: Why does this test fail?
					//Assertion.AssertEquals( "1234AF1.5!!oo..", sb.ToString() );
=09
		}

		[Test]
		public void Replace() {
			StringBuilder sb =3D new StringBuilder( "Foobarbaz" );
=09
			sb.Replace( "bar", "!!!" );             /* Test same length replace =
in middle of string */
		=09
			Assertion.AssertEquals( "Foo!!!baz", sb.ToString() );
=09
			sb.Replace( "Foo", "ABcD" );            /* Test longer replace at =
start of string */
=09
			Assertion.AssertEquals( "ABcD!!!baz", sb.ToString() );
=09
			sb.Replace( "baz", "00" );              /* Test shorter replace at =
end of string */
			=09
			Assertion.AssertEquals( "ABcD!!!00", sb.ToString() );
=09
			sb.Replace( sb.ToString(), null );      /* Test string clear as in =
spec */
=09
			Assertion.AssertEquals( String.Empty, sb.ToString() );
=09
			/*           |         10        20        30
			/*         |0123456789012345678901234567890| */
			sb.Append( "abc this is testing abc the abc abc partial replace abc" =
);
=09
			sb.Replace( "abc", "!!!", 0, 31 ); /* Partial replace at start of =
string */
=09
			Assertion.AssertEquals( "!!! this is testing !!! the !!! abc partial =
replace abc", sb.ToString() );
=09
			sb.Replace( "testing", "", 0, 15 ); /* Test replace across boundary =
*/
=09
			Assertion.AssertEquals( "!!! this is testing !!! the !!! abc partial =
replace abc", sb.ToString() );
=09
			sb.Replace( "!!!", "" ); /* Test replace with empty string */
=09
			Assertion.AssertEquals(" this is testing  the  abc partial replace =
abc", sb.ToString() );
		}

		[Test]
		public void AppendFormat() {
		}
	}

}

------=_NextPart_000_0001_01C2C7BE.41120990
Content-Type: application/octet-stream;
	name="run_test.sh"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="run_test.sh"

#!/bin/sh=0A=
=0A=
if [ $# -eq 0 ]; then=0A=
	echo "You should give a list of test names such as: "=0A=
	echo "$0 System.IO.FileTest System.Text.StringBuilderTest"=0A=
	echo "or"=0A=
	echo "$0 System.AllTests"=0A=
	echo "and so on..."=0A=
	exit 1=0A=
fi=0A=
=0A=
topdir=3D../../..=0A=
NUNITCONSOLE=3D${topdir}/nunit20/nunit-console.exe=0A=
=0A=
for i in $@; do=0A=
	MONO_PATH=3D${topdir}/nunit20:. \=0A=
	mono ${NUNITCONSOLE} /fixture:MonoTests.${i} corlib_test.dll=0A=
done=0A=
=0A=

------=_NextPart_000_0001_01C2C7BE.41120990--