瀏覽代碼

2002-08-12 Franklin Wise <[email protected]>

	* System.Data/Constraint.cs: Implemented

	* System.Data/UniqueConstraint.cs: GetHashCode() &
	special case Ctor. Still need to be implemented. LAMESPEC tags
	added.

	* System.Data/ConstraintCollection.cs: Clear() &
	AddRange() need to be finished. Several LAMESPEC tags.

	* Allow Constraint collection to be created in DataTable.

	* System.Data/ForeignKeyConstraint: Added a couple of
	helper functions.

	* System.Data/DataColumnCollection New/Added DataColumns now have
	Table property set.

svn path=/trunk/mcs/; revision=6611
Rodrigo Moya 23 年之前
父節點
當前提交
424c67c8bb

+ 19 - 0
mcs/class/System.Data/ChangeLog

@@ -1,3 +1,22 @@
+2002-08-12  Franklin Wise <[email protected]>
+
+	* System.Data/Constraint.cs: Implemented
+
+	* System.Data/UniqueConstraint.cs: GetHashCode() &
+	special case Ctor. Still need to be implemented. LAMESPEC tags
+	added.
+
+	* System.Data/ConstraintCollection.cs: Clear() &
+	AddRange() need to be finished. Several LAMESPEC tags.
+
+	* Allow Constraint collection to be created in DataTable.
+
+	* System.Data/ForeignKeyConstraint: Added a couple of
+	helper functions.
+
+	* System.Data/DataColumnCollection New/Added DataColumns now have
+	Table property set.
+
 2002-08-11  Rodrigo Moya <[email protected]>
 
 	* System.Data.OleDb/libgda.cs: added some GdaValue functions.

+ 52 - 20
mcs/class/System.Data/System.Data/Constraint.cs

@@ -2,7 +2,9 @@
 // System.Data.Constraint.cs
 //
 // Author:
-//   Daniel Morgan
+//	Franklin Wise <[email protected]>
+//	Daniel Morgan
+//   
 //
 // (C) Ximian, Inc. 2002
 //
@@ -16,32 +18,44 @@ using System.Runtime.Serialization;
 namespace System.Data
 {
 	[Serializable]
-	public abstract class Constraint {
+	internal delegate void DelegateConstraintNameChange(object sender,
+			string newName);
+	
+	[Serializable]
+	public abstract class Constraint 
+	{
+		internal event DelegateConstraintNameChange 
+					BeforeConstraintNameChange;
+
+		private string _name = null;
+		private PropertyCollection _properties = null;
 
-		protected string name = null;
-		protected PropertyCollection properties = null;
+		//Used for membership checking
+		private ConstraintCollection _constraintCollection;
 
-		[MonoTODO]
-		protected Constraint() {
-			properties = new PropertyCollection();
+		protected Constraint() 
+		{
+			_properties = new PropertyCollection();
 		}
 
 		public virtual string ConstraintName {
-			[MonoTODO]	
 			get{
-				return name;
+				return "" + _name;
 			} 
 
-			[MonoTODO]
 			set{
-				name = value;
+				//This should only throw an exception when it
+				//is a member of a ConstraintCollection which
+				//means we should let the ConstraintCollection
+				//handle exceptions when this value changes
+				_onConstraintNameChange(value);
+				_name = value;
 			}
 		}
 
 		public PropertyCollection ExtendedProperties {
-			[MonoTODO]
 			get {
-				return properties;
+				return _properties;
 			}
 		}
 
@@ -49,14 +63,32 @@ namespace System.Data
 			get;
 		}
 
-		[MonoTODO]
-		public override string ToString() {
-			return name;
+		/// <summary>
+		/// Gets the ConstraintName, if there is one, as a string. 
+		/// </summary>
+		public override string ToString() 
+		{
+			return "" + _name;
+		}
+
+		internal ConstraintCollection ConstraintCollection {
+			get{
+				return _constraintCollection;
+			}
+			set{
+				_constraintCollection = value;
+			}
+		}
+		
+
+
+		private void _onConstraintNameChange(string newName)
+		{
+			if (null != BeforeConstraintNameChange)
+			{
+				BeforeConstraintNameChange(this, newName);
+			}
 		}
 
-		//[MonoTODO]
-		//[ClassInterface(ClassInterfaceType.AutoDual)]
-		//~Constraint() {
-		//}
 	}
 }

+ 237 - 57
mcs/class/System.Data/System.Data/ConstraintCollection.cs

@@ -2,9 +2,11 @@
 // System.Data.ConstraintCollection.cs
 //
 // Author:
+//   Franklin Wise <[email protected]>
 //   Daniel Morgan
-//
+//   
 // (C) Ximian, Inc. 2002
+// (C) 2002 Franklin Wise
 // (C) 2002 Daniel Morgan
 //
 
@@ -14,63 +16,166 @@ using System.ComponentModel;
 
 namespace System.Data
 {
+	[Serializable]
+	internal delegate void DelegateValidateRemoveConstraint(ConstraintCollection sender,
+			Constraint constraintToRemove, ref bool cancel);
+	
 	/// <summary>
 	/// hold collection of constraints for data table
 	/// </summary>
-	public class ConstraintCollection : InternalDataCollectionBase {
+	[Serializable]
+	public class ConstraintCollection : InternalDataCollectionBase 
+	{
+		private bool beginInit = false;
+		
+		public event CollectionChangeEventHandler CollectionChanged;
+		internal event DelegateValidateRemoveConstraint ValidateRemoveConstraint;
+		
+		//Don't allow public instantiation
+		//Will be instantianted from DataTable
+		internal ConstraintCollection(){} 
 
 		public virtual Constraint this[string name] {
-			[MonoTODO]
 			get {
-				throw new NotImplementedException ();
+				int index = IndexOf(name);
+				if (-1 == index) return null;
+				return this[index];
 			}
 		}
 		
 		public virtual Constraint this[int index] {
-			[MonoTODO]
 			get {
-				throw new NotImplementedException ();
+				return (Constraint)List[index];
+			}
+		}
+
+		private void _handleBeforeConstraintNameChange(object sender, string newName)
+		{
+			//null or empty
+			if (newName == null || newName == "") 
+				throw new ArgumentException("ConstraintName cannot be set to null or empty " +
+					" after it has been added to a ConstraintCollection.");
+
+			if (_isDuplicateConstraintName(newName,(Constraint)sender))
+				throw new DuplicateNameException("Constraint name already exists.");
+		}
+
+		private bool _isDuplicateConstraintName(string constraintName, Constraint excludeFromComparison) 
+		{	
+			string cmpr = constraintName.ToUpper();
+			foreach (Constraint cst in List) 
+			{
+				//Case insensitive comparision
+				if (  cmpr.CompareTo(cst.ConstraintName.ToUpper()) == 0  &&
+					cst != excludeFromComparison) 
+				{
+					return true;
+				}
 			}
+
+			return false;
 		}
+		
+		//finds an open name slot of ConstraintXX
+		//where XX is a number
+		private string _createNewConstraintName() 
+		{
+			bool loopAgain = false;
+			int index = 1;
 
+			do
+			{	
+				loopAgain = false;
+				foreach (Constraint cst in List) 
+				{
+					//Case insensitive
+					if (cst.ConstraintName.ToUpper().CompareTo("CONSTRAINT" + 
+						index.ToString()) == 0 ) 
+					{
+						loopAgain = true;
+						index++;
+					}
+				}
+			} while (loopAgain);
+
+			return "Constraint" + index.ToString(); 	
+			
+		}
+		
+		
 		// Overloaded Add method (5 of them)
 		// to add Constraint object to the collection
 
-		[MonoTODO]
-		public void Add(Constraint constraint) {
+		public void Add(Constraint constraint) 
+		{		
+			//not null
+			if (null == constraint) throw new ArgumentNullException("Can not add null.");
 			
-			throw new NotImplementedException ();
+			//check constraint membership 
+			//can't already exist in this collection or any other
+			if (this == constraint.ConstraintCollection) 
+				throw new ArgumentException("Constraint already belongs to this collection.");
+			if (null != constraint.ConstraintCollection) 
+				throw new ArgumentException("Constraint already belongs to another collection.");
+			
+			//check for duplicate
+			if (_isDuplicateConstraintName(constraint.ConstraintName,null)  )
+				throw new DuplicateNameException("Constraint name already exists.");
+		
+			//if name is null or empty give it a name
+			if (constraint.ConstraintName == null || 
+				constraint.ConstraintName == "" ) 
+			{ 
+				constraint.ConstraintName = _createNewConstraintName();
+			}
+
+			//Add event handler for ConstraintName change
+			constraint.BeforeConstraintNameChange += new DelegateConstraintNameChange(
+				_handleBeforeConstraintNameChange);
+			
+			constraint.ConstraintCollection = this;
+			List.Add(constraint);
+
+			OnCollectionChanged( new CollectionChangeEventArgs( CollectionChangeAction.Add, this) );
 		}
 
-		[MonoTODO]
-		public virtual Constraint Add(string name,
-			DataColumn column, bool primaryKey) {
+	
 
-			throw new NotImplementedException ();
+		public virtual Constraint Add(string name, DataColumn column, bool primaryKey) 
+		{
 
+			UniqueConstraint uc = new UniqueConstraint(name, column, primaryKey);
+			Add(uc);
+			 
+			return uc;
 		}
 
-		[MonoTODO]
-		public virtual Constraint Add(string name,
-			DataColumn primaryKeyColumn,
-			DataColumn foreignKeyColumn) {
+		public virtual Constraint Add(string name, DataColumn primaryKeyColumn,
+			DataColumn foreignKeyColumn) 
+		{
+			ForeignKeyConstraint fc = new ForeignKeyConstraint(name, primaryKeyColumn, 
+					foreignKeyColumn);
+			Add(fc);
 
-			throw new NotImplementedException ();
+			return fc;
 		}
 
-		[MonoTODO]
-		public virtual Constraint Add(string name,
-			DataColumn[] columns, bool primaryKey) {
+		public virtual Constraint Add(string name, DataColumn[] columns, bool primaryKey) 
+		{
+			UniqueConstraint uc = new UniqueConstraint(name, columns, primaryKey);
+			Add(uc);
 
-			throw new NotImplementedException ();
+			return uc;
 		}
 
-		[MonoTODO]
-		public virtual Constraint Add(string name,
-			DataColumn[] primaryKeyColumns,
-			DataColumn[] foreignKeyColumns) {
+		public virtual Constraint Add(string name, DataColumn[] primaryKeyColumns,
+			DataColumn[] foreignKeyColumns) 
+		{
+			ForeignKeyConstraint fc = new ForeignKeyConstraint(name, primaryKeyColumns, 
+					foreignKeyColumns);
+			Add(fc);
 
-			throw new NotImplementedException ();
+			return fc;
 		}
 
 		[MonoTODO]
@@ -79,63 +184,138 @@ namespace System.Data
 			throw new NotImplementedException ();
 		}
 
-		[MonoTODO]
-		public bool CanRemove(Constraint constraint) {
+		public bool CanRemove(Constraint constraint) 
+		{
 
-			throw new NotImplementedException ();
+			//Rule A UniqueConstraint can't be removed if there is
+			//a foreign key relationship to that column
+
+			//not null 
+			//LAMESPEC: MSFT implementation throws and exception here
+			//spec says nothing about this
+			if (null == constraint) throw new ArgumentNullException("Constraint can't be null.");
+			
+			//if we are not a unique constraint then it's ok to remove
+			UniqueConstraint uc = constraint as UniqueConstraint;
+			if (null == uc) return true;
+
+			//LAMESPEC: spec says return false (which makes sense) and throw exception for False case (?).
+			//discover if there is a related ForeignKey
+			return _canRemoveConstraint(constraint);
+			
 		}
 
 		[MonoTODO]
-		public void Clear() {
+		public void Clear() 
+		{
 			
-			throw new NotImplementedException ();
+			//CanRemove? See Lamespec below.
+
+			//the Constraints have a reference to us
+			//and we listen to name change events 
+			//we should remove these before clearing
+			foreach (Constraint con in List)
+			{
+				con.ConstraintCollection = null;
+				con.BeforeConstraintNameChange -= new DelegateConstraintNameChange(
+				_handleBeforeConstraintNameChange);
+			}
+
+			//LAMESPEC: MSFT implementation allows this
+			//even when a ForeignKeyConstraint exist for a UniqueConstraint
+			//thus violating the CanRemove logic
+			List.Clear(); //Will violate CanRemove rule
+			OnCollectionChanged( new CollectionChangeEventArgs(CollectionChangeAction.Refresh, this) );
 		}
 
-		[MonoTODO]
-		public bool Contains(string name) {
-			throw new NotImplementedException ();
+		public bool Contains(string name) 
+		{
+			return (-1 != IndexOf(name));
 		}
 
-		[MonoTODO]
-		public int IndexOf(Constraint constraint) {
-			throw new NotImplementedException ();
+		public int IndexOf(Constraint constraint) 
+		{
+			return List.IndexOf(constraint);
 		}
 
-		[MonoTODO]
-		public virtual int IndexOf(string constraintName) {
-			throw new NotImplementedException ();
+		public virtual int IndexOf(string constraintName) 
+		{
+			//LAMESPEC: Spec doesn't say case insensitive
+			//it should to be consistant with the other 
+			//case insensitive comparisons in this class
+
+			int index = 0;
+			foreach (Constraint con in List)
+			{
+				if (constraintName.ToUpper().CompareTo( con.ConstraintName.ToUpper() ) == 0)
+				{
+					return index;
+				}
+
+				index++;
+			}
+			return -1; //not found
 		}
 
-		[MonoTODO]
 		public void Remove(Constraint constraint) {
-			throw new NotImplementedException ();
+			//LAMESPEC: spec doesn't document the ArgumentException the
+			//will be thrown if the CanRemove rule is violated
+			
+			//LAMESPEC: spec says an exception will be thrown
+			//if the element is not in the collection. The implementation
+			//doesn't throw an exception. ArrayList.Remove doesn't throw if the
+			//element doesn't exist
+			//ALSO the overloaded remove in the spec doesn't say it throws any exceptions
+
+			//not null
+			if (null == constraint) throw new ArgumentNullException();
+
+			List.Remove(constraint);
+			OnCollectionChanged( new CollectionChangeEventArgs(CollectionChangeAction.Remove,this));
 		}
 
-		[MonoTODO]
-		public void Remove(string name) {
-			throw new NotImplementedException ();
+		public void Remove(string name) 
+		{
+			//if doesn't exist fail quietly
+			int index = IndexOf(name);
+			if (-1 == index) return;
+
+			Remove(this[index]);
 		}
 
-		[MonoTODO]
-		public void RemoveAt(int index) {
-			throw new NotImplementedException ();
+		public void RemoveAt(int index) 
+		{
+			if (index < 0 || index + 1 > List.Count)
+				throw new IndexOutOfRangeException("Index out of range, index = " 
+						+ index.ToString() + ".");
+	
+			List.RemoveAt(index);
+			OnCollectionChanged( new CollectionChangeEventArgs(CollectionChangeAction.Remove,this));
 		}
 
-		[MonoTODO]
-		public event CollectionChangeEventHandler CollectionChanged;
 
 		protected override ArrayList List {
-			[MonoTODO]
 			get{
-				throw new NotImplementedException ();
+				return base.List;
 			}
 		}
 
-		[MonoTODO]
-		protected virtual void OnCollectionChanged(
-			CollectionChangeEventArgs ccevent) {
+		protected virtual void OnCollectionChanged( CollectionChangeEventArgs ccevent) 
+		{
+			if (null != CollectionChanged)
+			{
+				CollectionChanged(this, ccevent);
+			}
+		}
 
-			throw new NotImplementedException ();
+		private bool _canRemoveConstraint(Constraint constraint )
+		{
+			bool cancel = false;
+			if (null != ValidateRemoveConstraint)
+			{
+				ValidateRemoveConstraint(this, constraint, ref cancel);
+			}
+			return !cancel;
 		}
 	}
 }

+ 6 - 5
mcs/class/System.Data/System.Data/DataColumn.cs

@@ -39,7 +39,7 @@ namespace System.Data
 		private int ordinal = -1;
 		private string prefix = null;
 		private bool readOnly = false;
-		private DataTable table = null;
+		private DataTable _table = null;
 		private bool unique = false;
 
 		#endregion // Fields
@@ -269,11 +269,11 @@ namespace System.Data
 				readOnly = value;
 			}
 		}
-
+	
 		public DataTable Table
 		{
 			get {
-				return table;
+				return _table;
 			}
 		}
 
@@ -324,8 +324,9 @@ namespace System.Data
 
 		[MonoTODO]
 		internal void SetTable(DataTable table) {
-			this.table = table; 
-			// FIXME: this will get called by DataTable
+			_table = table; 
+			// FIXME: this will get called by DataTable 
+			// and DataColumnCollection
 		}
 
 		#endregion // Methods

+ 7 - 0
mcs/class/System.Data/System.Data/DataColumnCollection.cs

@@ -84,6 +84,8 @@ namespace System.Data
 		{
 			DataColumn column = new DataColumn("Column" + defaultNameIndex.ToString());
 			CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Add, this);
+			
+			column.SetTable(parentTable);
 			base.List.Add(column);
 			OnCollectionChanged(e);
 			defaultNameIndex++;
@@ -103,6 +105,8 @@ namespace System.Data
 			else
 			{
 				CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Add, this);
+				
+				column.SetTable( parentTable);
 				base.List.Add(column);
 				OnCollectionChanged(e);
 				return;
@@ -132,6 +136,7 @@ namespace System.Data
 				DataColumn column = new DataColumn(columnName);
 				
 				CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Add, this);
+				column.SetTable(parentTable);
 				base.List.Add(column);
 				OnCollectionChanged(e);
 				return column;
@@ -160,6 +165,7 @@ namespace System.Data
 			{
 				DataColumn column = new DataColumn(columnName, type);
 				CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Add, this);
+				column.SetTable(parentTable);
 				base.List.Add(column);
 				OnCollectionChanged(e);
 				return column;
@@ -189,6 +195,7 @@ namespace System.Data
 			{
 				DataColumn column = new DataColumn(columnName, type, expression);
 				CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Add, this);
+				column.SetTable(parentTable);
 				base.List.Add(column);
 				OnCollectionChanged(e);
 				return column;

+ 1 - 1
mcs/class/System.Data/System.Data/DataTable.cs

@@ -60,7 +60,7 @@ namespace System.Data
 			dataSet = null;
 			// _defaultView = null; // FIXME: temporarily commented
 			_columnCollection = new DataColumnCollection(this);
-			//_constraintCollection = new ConstraintCollection(); TODO: uncomment after ConstraintCollection is built.
+			_constraintCollection = new ConstraintCollection(); 
 			_extendedProperties = null;
 			_tableName = "";
 			_nameSpace = null;

+ 2 - 0
mcs/class/System.Data/System.Data/ForeignKeyConstraint.cs

@@ -2,8 +2,10 @@
 // System.Data.ForeignKeyConstraint.cs
 //
 // Author:
+//   Franklin Wise <[email protected]>
 //   Daniel Morgan <[email protected]>
 //
+// (C) 2002 Franklin Wise
 // (C) 2002 Daniel Morgan
 //
 

+ 21 - 4
mcs/class/System.Data/System.Data/UniqueConstraint.cs

@@ -2,10 +2,11 @@
 // System.Data.UniqueConstraint.cs
 //
 // Author:
+//   Franklin Wise <[email protected]>
 //   Daniel Morgan <[email protected]>
-//
+//   
+// (C) 2002 Franklin Wise
 // (C) 2002 Daniel Morgan
-//
 
 using System;
 using System.Collections;
@@ -104,9 +105,25 @@ namespace System.Data
 
 		#region Methods
 
-		[MonoTODO]
 		public override bool Equals(object key2) {
-			throw new NotImplementedException ();
+			UniqueConstraint cst = key2 as UniqueConstraint;
+			if (null == cst) return false;
+
+			//according to spec if the cols are equal
+			//then two UniqueConstraints are equal
+			bool found = false;
+			foreach (DataColumn thisCol in this.Columns) {
+				found = false;
+				foreach (DataColumn col in cst.Columns) {
+					if (thisCol == col)
+						found = true;
+				}
+				if (false == found) return false;
+			}
+
+			//if we got here then all columns were found
+			return true;
+			
 		}
 
 		[MonoTODO]

+ 12 - 0
mcs/class/System.Data/Test/ChangeLog

@@ -1,3 +1,15 @@
+2002-08-12  Franklin Wise <[email protected]>
+	* NewFile: Added test for System.Data.UniqueConstraintTest.cs
+
+	* NewFile: Added test for System.Data.ConstraintTest.cs
+
+	* NewFile: Added test for System.Data.ConstraintCollection.cs
+
+	* Added blank test for DataColumnTest so that NUnit won't warn
+	of no tests
+
+	* Updated System.Data.AllTests.cs to include the new tests
+	
 2002-05-27  Tim Coleman <[email protected]>
 	* TestSqlDataAdapter.cs: remove explicit opening of connection.
 	This should occur implicitly now.

+ 3 - 0
mcs/class/System.Data/Test/System.Data/AllTests.cs

@@ -22,6 +22,9 @@ namespace MonoTests.System.Data
 			get {
 				TestSuite suite =  new TestSuite ();
 				suite.AddTest (new TestSuite (typeof (DataColumnTest)));
+				suite.AddTest (new TestSuite (typeof (UniqueConstraintTest)));
+				suite.AddTest (new TestSuite (typeof (ConstraintTest)));
+				suite.AddTest (new TestSuite (typeof (ConstraintCollectionTest)));
 				return suite;
 			}
 		}

+ 111 - 0
mcs/class/System.Data/Test/System.Data/ConstraintCollectionTest.cs

@@ -0,0 +1,111 @@
+// ConstraintCollection.cs - NUnit Test Cases for testing the ConstraintCollection 
+//	class.
+//	
+//
+// Franklin Wise ([email protected])
+//
+// (C) Franklin Wise
+// 
+
+
+using NUnit.Framework;
+using System;
+using System.Data;
+
+
+namespace MonoTests.System.Data
+{
+
+
+	public class ConstraintCollectionTest : TestCase 
+	{
+		private DataTable _table;
+		private Constraint _constraint1;
+		private Constraint _constraint2;
+
+		public ConstraintCollectionTest() : base ("MonoTests.System.Data.ConstraintCollectionTest") {}
+		public ConstraintCollectionTest(string name) : base(name) {}
+
+		public void PublicSetup(){SetUp();}
+		protected override void SetUp() 
+		{
+			//Setup DataTable
+			_table = new DataTable("TestTable");
+			_table.Columns.Add("Col1",typeof(int));
+			_table.Columns.Add("Col2",typeof(int));
+
+			//Use UniqueConstraint to test Constraint Base Class
+			_constraint1 = new UniqueConstraint(_table.Columns[0],false); 
+			_constraint2 = new UniqueConstraint(_table.Columns[1],false); 
+		}
+
+		protected override void TearDown() {}
+
+		public static ITest Suite 
+		{
+			get 
+			{ 
+				return new TestSuite(typeof(ConstraintCollectionTest)); 
+			}
+		}
+
+		public void TestAdd()
+		{
+			ConstraintCollection col = _table.Constraints;
+			col.Add(_constraint1);
+			col.Add(_constraint2);
+
+			Assertion.AssertEquals("Count doesn't equal added.",2, col.Count);
+		}
+
+		public void TestAddExceptions()
+		{
+			ConstraintCollection col = _table.Constraints;
+			try 
+			{
+				col.Add(null);
+				Assertion.Fail("B1: Failed to throw ArgumentNullException.");
+			}
+			catch (ArgumentNullException) {}
+			catch (AssertionFailedError exc) {throw exc;}
+			catch 
+			{
+				Assertion.Fail("A1: Wrong exception type");
+			}
+
+			try 
+			{
+				_constraint1.ConstraintName = "Dog";
+				_constraint2.ConstraintName = "dog"; //case insensitive
+				col.Add(_constraint1);
+				col.Add(_constraint2);
+				Assertion.Fail("Failed to throw Duplicate name exception.");
+			}
+			catch (DuplicateNameException) {}
+			catch (AssertionFailedError exc) {throw exc;}
+			catch (Exception exc)
+			{
+				Assertion.Fail("A2: Wrong exception type. " + exc.ToString());
+			}
+
+			//Constraint Already exists
+			try 
+			{
+				col.Add(_constraint1);
+				Assertion.Fail("B2: Failed to throw ArgumentException.");
+			}
+			catch (ArgumentException) {}
+			catch (AssertionFailedError exc) {throw exc;}
+			catch 
+			{
+				Assertion.Fail("A3: Wrong exception type");
+			}
+		}
+
+		public void TestRemoveExceptions()
+		{
+
+
+		}
+	}
+}

+ 132 - 0
mcs/class/System.Data/Test/System.Data/ConstraintTest.cs

@@ -0,0 +1,132 @@
+// ConstraintTest.cs - NUnit Test Cases for testing the abstract class System.Data.Constraint
+// The tests use an inherited class (UniqueConstraint) to test the Constraint class.
+//
+// Franklin Wise <[email protected]>
+//
+// (C) 2002 Franklin Wise
+// 
+
+using NUnit.Framework;
+using System;
+using System.Data;
+
+namespace MonoTests.System.Data
+{
+//	public class MyUniqueConstraint: UniqueConstraint {
+//		public MyUniqueConstraint(DataColumn col, bool pk): base(col,pk){}
+//		string _myval = "";
+//		public override string ConstraintName {
+//			get{
+//				return _myval;
+//				return base.ConstraintName;
+//			}
+//			set{
+//				Console.WriteLine("NameSet = " + value);
+//				base.ConstraintName = value;
+//				_myval = value;
+//			}
+//		}
+//	}
+
+	public class ConstraintTest : TestCase 
+	{
+		private DataTable _table;
+		private Constraint _constraint1;
+		private Constraint _constraint2;
+
+		public ConstraintTest() : base ("MonoTests.System.Data.ConstraintTest") {}
+		public ConstraintTest(string name) : base(name) {}
+
+		public void PublicSetup(){SetUp();}
+		protected override void SetUp() {
+
+			//Setup DataTable
+			_table = new DataTable("TestTable");
+			_table.Columns.Add("Col1",typeof(int));
+			_table.Columns.Add("Col2",typeof(int));
+
+			//Use UniqueConstraint to test Constraint Base Class
+			_constraint1 = new UniqueConstraint(_table.Columns[0],false); 
+			_constraint2 = new UniqueConstraint(_table.Columns[1],false); 
+
+		}  
+		
+
+		protected override void TearDown() {}
+
+		public static ITest Suite {
+			get { 
+				return new TestSuite(typeof(ConstraintTest)); 
+			}
+		}
+
+		public void TestSetConstraintNameNullOrEmptyExceptions() {
+			bool exceptionCaught = false;
+			string name = null;
+
+			_table.Constraints.Add (_constraint1);  
+
+			Console.WriteLine(_constraint1.ConstraintName);
+
+			for (int i = 0; i <= 1; i++) {
+				exceptionCaught = false;
+				if (0 == i) name = null;
+				if (1 == i) name = String.Empty;
+	
+				try {
+				
+					//Next line should throw ArgumentException
+					//Because ConstraintName can't be set to null
+					//or empty while the constraint is part of the
+					//collection
+					_constraint1.ConstraintName = name; 
+				}
+				catch (ArgumentException){ 
+					exceptionCaught = true;
+				}
+				catch {
+					Assertion.Fail("Wrong exception type thrown.");
+				}
+				
+				Assertion.Assert("Failed to throw exception.",
+					true == exceptionCaught);
+			}	
+		}
+
+		public void TestSetConstraintNameDuplicateException() {
+			_constraint1.ConstraintName = "Dog";
+			_constraint2.ConstraintName = "Cat";
+
+			_table.Constraints.Add(_constraint1);
+			_table.Constraints.Add(_constraint2);
+
+			try {
+				//Should throw DuplicateNameException
+				_constraint2.ConstraintName = "Dog";
+			
+				Assertion.Fail("Failed to throw " + 
+					" DuplicateNameException exception.");
+			}	
+			catch (DuplicateNameException) {}
+			catch (AssertionFailedError exc) {throw exc;}
+			catch {
+				Assertion.Fail("Wrong exception type thrown.");
+			}
+		
+		}
+
+		public void TestToString() {
+			//_constraint1.ConstraintName = "Test";
+			Assertion.Assert("ToString is the same as constraint name.", _constraint1.ConstraintName.CompareTo( _constraint1.ToString()) == 0);
+		}
+
+		public void TestGetExtendedProperties() {
+			PropertyCollection col = _constraint1.ExtendedProperties as
+				PropertyCollection;
+
+			Assertion.AssertNotNull("ExtendedProperties returned null or didn't " +
+				"return the correct type", col);
+		}
+		
+	}
+}

+ 2 - 0
mcs/class/System.Data/Test/System.Data/DataColumnTest.cs

@@ -26,5 +26,7 @@ namespace MonoTests.System.Data
 				return new TestSuite (typeof (DataColumnTest)); 
 			}
 		}
+
+		public void TestBlank()	{} //Remove me when we add some tests
 	}
 }

+ 171 - 0
mcs/class/System.Data/Test/System.Data/UniqueConstraintTest.cs

@@ -0,0 +1,171 @@
+// UniqueConstraintTest.cs - NUnit Test Cases for testing the class System.Data.UniqueConstraint
+//
+// Franklin Wise <[email protected]>
+//
+// (C) 2002 Franklin Wise
+// 
+
+using NUnit.Framework;
+using System;
+using System.Data;
+
+namespace MonoTests.System.Data
+{
+	public class UniqueConstraintTest : TestCase 
+	{
+		private DataTable _table;
+
+		public UniqueConstraintTest() : base ("MonoTests.System.Data.UniqueConstraintTest") {}
+		public UniqueConstraintTest(string name) : base(name) {}
+	
+		public void PublicSetup() {this.SetUp();}
+		protected override void SetUp() {
+
+			//Setup DataTable
+			_table = new DataTable("TestTable");
+			_table.Columns.Add("Col1",typeof(int));
+			_table.Columns.Add("Col2",typeof(int));
+
+		}  
+
+		protected override void TearDown() {}
+
+		public static ITest Suite {
+			get { 
+				return new TestSuite(typeof(UniqueConstraintTest)); 
+			}
+		}
+
+		public void TestCtorExceptions() {
+			//UniqueConstraint(string name, DataColumn column, bool isPrimaryKey)
+
+			UniqueConstraint cst;
+			
+			//must have DataTable exception
+			try{
+				//Should throw an ArgumentException
+				//Can only add DataColumns that are attached
+				//to a DataTable
+				cst = new UniqueConstraint(new DataColumn(""));
+
+				Assertion.Fail("Failed to throw ArgumentException.");
+			}
+			catch (ArgumentException) {}
+			catch (AssertionFailedError exc) {throw exc;}
+			catch {
+				Assertion.Fail("A1: Wrong Exception type.");
+			}	
+
+			//Null exception
+			try {
+				//Should throw argument null exception
+				cst = new UniqueConstraint((DataColumn)null);
+			}
+			catch (ArgumentNullException) {}
+			catch (AssertionFailedError exc) {throw exc;}
+			catch {
+				Assertion.Fail("A2: Wrong Exception type.");
+			}
+
+			
+			try {
+				//Should throw exception
+				//must have at least one valid column
+				//InvalidConstraintException is thrown by msft ver
+				cst = new UniqueConstraint(new DataColumn [] {});
+
+				Assertion.Fail("B1: Failed to throw InvalidConstraintException.");
+			}
+			catch (InvalidConstraintException) {}
+			catch (AssertionFailedError exc) {throw exc;}
+			catch {
+				Assertion.Fail("A3: Wrong Exception type.");
+			}
+
+			DataTable dt = new DataTable("Table1");
+			dt.Columns.Add("Col1",typeof(int));
+			DataTable dt2 = new DataTable("Table2");
+			dt2.Columns.Add("Col1",typeof(int));
+
+			DataSet ds = new DataSet();
+			ds.Tables.Add(dt);
+			ds.Tables.Add(dt2);
+
+			//columns from two different tables.
+			try {
+				//next line should throw
+				//can't have columns from two different tables
+				cst = new UniqueConstraint(new DataColumn [] { 
+						 dt.Columns[0], dt2.Columns[0]});
+
+				Assertion.Fail("B2: Failed to throw InvalidConstraintException");
+			}
+			catch (InvalidConstraintException) {}
+			catch (AssertionFailedError exc) {throw exc;}
+			catch {
+				Assertion.Fail("A4: Wrong Exception type.");
+			}
+			
+
+			
+		}
+
+
+		public void TestCtor() {
+			
+			UniqueConstraint cst;
+		
+			//Success case
+			try {
+				cst = new UniqueConstraint(_table.Columns[0]);
+			}
+			catch (Exception exc) {
+				Assertion.Fail("A1: Failed to ctor. " + exc.ToString());
+			}
+
+			
+			try {
+				cst = new UniqueConstraint( new DataColumn [] {
+						_table.Columns[0], _table.Columns[1]});
+			}
+			catch (Exception exc) {
+				Assertion.Fail("A2: Failed to ctor. " + exc.ToString());
+			}
+
+			
+			//table is set on ctor
+			cst = new UniqueConstraint(_table.Columns[0]);
+			
+			Assertion.AssertSame("B1", cst.Table, _table);
+
+			//table is set on ctor
+			cst = new UniqueConstraint( new DataColumn [] {
+				      _table.Columns[0], _table.Columns[1]});
+			Assertion.AssertSame ("B2", cst.Table, _table);
+
+		
+		}
+
+		public void TestEquals() {
+			UniqueConstraint cst = new UniqueConstraint( new DataColumn [] {
+					_table.Columns[0], _table.Columns[1]});
+			UniqueConstraint cst2 = new UniqueConstraint( new DataColumn [] {
+					_table.Columns[0], _table.Columns[1]});
+
+			UniqueConstraint cst3 = new UniqueConstraint(_table.Columns[0]);
+			
+			//true
+			Assertion.Assert(cst.Equals(cst2) == true);
+			
+			//false
+			Assertion.Assert(cst.Equals(23) == false);
+			Assertion.Assert(cst.Equals(cst3) == false);
+
+
+		}
+
+
+	
+		
+	}
+}