Kaynağa Gözat

Added new tests for various System.Data classes. More flushing out of
the DataTable and supporting classes.

svn path=/trunk/mcs/; revision=7257

Franklin Wise 23 yıl önce
ebeveyn
işleme
f6b277b235

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

@@ -1,3 +1,32 @@
+2002-09-04  Franklin Wise <[email protected]>
+	
+	* Tests:  See Changelog for System.Data/Test
+	
+	* New Files:
+		System.Data/DataColumnCollectionTest.cs
+		System.Data/DataRowCollectionTest.cs
+		System.Data/DataRowTest.cs
+
+	* System.Data/DataColumn.cs:  Flushing out validation, type conversion for
+	autoincrement.  Added lots of TODO's.
+	* System.Data/DataColumnCollection.cs:  Wrote out add logic as a comment.
+	Tagged implementation with FIXME tags.  Lot's more validation
+	and setup needs to be done, much of which is now tagged as todo's
+	or FIXME's
+
+	* System.Data/DataRow.cs: Lot's of fixme's added.
+	
+	* System.Data/DataRowCollection.cs: TODO's added.
+
+	* System.Data/DataTable.cs:  Implemented PrimaryKey.  
+
+	* System.Data/UniqueConstraint.cs: Implemented related PrimaryKey
+	helpers.
+
+	
+	
+	
+		
 2002-08-25  Rodrigo Moya <[email protected]>
 
 	* System.Data.OleDb/OleDbTransaction.cs (OleDbTransaction): manage

+ 87 - 39
mcs/class/System.Data/System.Data/DataColumn.cs

@@ -2,10 +2,12 @@
 // System.Data.DataColumn.cs
 //
 // Author:
+//   Franklin Wise ([email protected])
 //   Christopher Podurgiel ([email protected])
 //   Rodrigo Moya ([email protected])
 //   Daniel Morgan ([email protected])
 //
+// (C) Copyright 2002, Franklin Wise
 // (C) Chris Podurgiel
 // (C) Ximian, Inc 2002
 //
@@ -38,14 +40,14 @@ namespace System.Data
 		
 		#region Fields
 
-		private bool allowDBNull = true;
-		private bool autoIncrement = false;
-		private long autoIncrementSeed = 0;
-		private long autoIncrementStep = 1;
-		private string caption = null;
-		private MappingType columnMapping = MappingType.Element;
-		private string columnName = null;
-		private Type dataType = null;
+		private bool _allowDBNull = true;
+		private bool _autoIncrement = false;
+		private long _autoIncrementSeed = 0;
+		private long _autoIncrementStep = 1;
+		private string _caption = null;
+		private MappingType _columnMapping = MappingType.Element;
+		private string _columnName = null;
+		private Type _dataType = null;
 		private object defaultValue = null;
 		private string expression = null;
 		private PropertyCollection extendedProperties = null;
@@ -65,6 +67,7 @@ namespace System.Data
 		{
 		}
 
+		//TODO: Ctor init vars directly
 		public DataColumn(string columnName): this()
 		{
 			ColumnName = columnName;
@@ -73,7 +76,7 @@ namespace System.Data
 		public DataColumn(string columnName, Type dataType): this(columnName)
 		{
 			if(dataType == null) {
-				throw new ArgumentNullException();
+				throw new ArgumentNullException("dataType can't be null.");
 			}
 			
 			DataType = dataType;
@@ -98,10 +101,29 @@ namespace System.Data
 		public bool AllowDBNull
 		{
 			get {
-				return allowDBNull;
+				return _allowDBNull;
 			}
 			set {
-				allowDBNull = value;
+				//TODO: If we are a part of the table and this value changes
+				//we need to validate that all the existing values conform to the new setting
+
+				if (true == value)
+				{
+					_allowDBNull = true;
+					return;
+				}
+				
+				//if Value == false case
+				if (null != _table)
+				{
+					if (_table.Rows.Count > 0)
+					{
+						//TODO: Validate no null values exist
+						//do we also check different versions of the row??
+					}
+				}
+					
+				_allowDBNull = value;
 			}
 		}
         
@@ -117,92 +139,104 @@ namespace System.Data
 		public bool AutoIncrement
 		{
 			get {
-				return autoIncrement;
+				return _autoIncrement;
 			}
 			set {
-				autoIncrement = value;
-				if(autoIncrement == true)
+				if(value == true)
 				{
+					//Can't be true if this is a computed column
 					if(Expression != null)
 					{
-						throw new Exception();
+						throw new ArgumentException("Can't Auto Increment a computed column."); 
 					}
-					if(Type.GetTypeCode(dataType) != TypeCode.Int16 && 
-					   Type.GetTypeCode(dataType) != TypeCode.Int32 && 
-					   Type.GetTypeCode(dataType) != TypeCode.Int64)
+
+					//If the DataType of this Column isn't an Int
+					//Make it an int
+					if(Type.GetTypeCode(_dataType) != TypeCode.Int16 && 
+					   Type.GetTypeCode(_dataType) != TypeCode.Int32 && 
+					   Type.GetTypeCode(_dataType) != TypeCode.Int64)
 					{
-						Int32 dtInt = new Int32();
-						dataType = dtInt.GetType();
+						_dataType = typeof(Int32); 
 					}
 				}
+				_autoIncrement = value;
 			}
 		}
 
 		public long AutoIncrementSeed
 		{
 			get {
-				return autoIncrementSeed;
+				return _autoIncrementSeed;
 			}
 			set {
-				autoIncrementSeed = value;
+				_autoIncrementSeed = value;
 			}
 		}
 
 		public long AutoIncrementStep
 		{
 			get {
-				return autoIncrementStep;
+				return _autoIncrementStep;
 			}
 			set {
-				autoIncrementStep = value;
+				_autoIncrementStep = value;
 			}
 		}
 
 		public string Caption 
 		{
 			get {
-				if(caption == null)
-					return columnName;
+				if(_caption == null)
+					return ColumnName;
 				else
-					return caption;
+					return _caption;
 			}
 			set {
-				caption = value;
+				_caption = value;
 			}
 		}
 
 		public virtual MappingType ColumnMapping
 		{
 			get {
-				return columnMapping;
+				return _columnMapping;
 			}
 			set {
-				columnMapping = value;
+				_columnMapping = value;
 			}
 		}
 
 		public string ColumnName
 		{
 			get {
-				return columnName;
+				return "" + _columnName;
 			}
 			set {
-				columnName = value;
+				//Both are checked after the column is part of the collection
+				//TODO: Check Name duplicate
+				//TODO: check Name != null
+				_columnName = value;
 			}
 		}
 
 		public Type DataType
 		{
 			get {
-				return dataType;
+				return _dataType;
 			}
 			set {
+				//TODO: check if data already exists can we change the datatype
+
+				//TODO: we want to check that the datatype is supported?
+				
+				//Check AutoIncrement status, make compatible datatype
+				//TODO: Check for other int values i.e. Int16 etc
 				if(AutoIncrement == true && 
 				   Type.GetTypeCode(value) != TypeCode.Int32)
 				{
-					throw new Exception();
+					throw new Exception(); //TODO: correction exception type
 				}
-				dataType = value;
+				_dataType = value;
 			}
 		}
 
@@ -220,13 +254,15 @@ namespace System.Data
 			}
 		}
 
+		[MonoTODO]
 		public string Expression
 		{
 			get {
 				return expression;
 			}
 			set {
-				expression = value;
+				//TODO: validation of the expression
+				expression = value;  //Check?
 			}
 		}
 
@@ -292,12 +328,16 @@ namespace System.Data
 			}
 		}
 
+		[MonoTODO]
 		public bool Unique
 		{
 			get {
 				return unique;
 			}
 			set {
+				//TODO: create UniqueConstraint
+				//if Table == null then the constraint is 
+				//created on addition to the collection
 				unique = value;
 			}
 		}
@@ -305,7 +345,8 @@ namespace System.Data
 		#endregion // Properties
 
 		#region Methods
-
+		
+/* ??
 		[MonoTODO]
 		protected internal void CheckNotAllowNull() {
 		}
@@ -313,7 +354,14 @@ namespace System.Data
 		[MonoTODO]
 		protected void CheckUnique() {
 		}
+*/
 
+		[MonoTODO]
+		internal void AssertCanAddToCollection()
+		{
+			//Check if Default Value is set and AutoInc is set
+		}
+		
 		[MonoTODO]
 		protected internal virtual void 
 		OnPropertyChanging (PropertyChangedEventArgs pcevent) {
@@ -334,13 +382,13 @@ namespace System.Data
 			if (expression != null)
 				return expression;
 			
-			return columnName;
+			return ColumnName;
 		}
 
 		[MonoTODO]
 		internal void SetTable(DataTable table) {
 			_table = table; 
-			// FIXME: this will get called by DataTable 
+			// this will get called by DataTable 
 			// and DataColumnCollection
 		}
 

+ 34 - 4
mcs/class/System.Data/System.Data/DataColumnCollection.cs

@@ -18,6 +18,9 @@ namespace System.Data
 	/// </summary>
 	public class DataColumnCollection : InternalDataCollectionBase
 	{
+		
+
+		
 		// The defaultNameIndex is used to create a default name for a column if one wasn't given.
 		private int defaultNameIndex;
 
@@ -76,12 +79,26 @@ namespace System.Data
 			}
 		}
 
+
+		//Add Logic
+		//
+		//Changing Event
+		//DefaultValue set and AutoInc set check
+		//?Validate Expression??
+		//Name check and creation
+		//Set Table
+		//Check Unique if true then add a unique constraint
+		//?Notify Rows of new column ?
+		//Add to collection
+		//Changed Event
+
 		/// <summary>
 		/// Creates and adds a DataColumn object to the DataColumnCollection.
 		/// </summary>
 		/// <returns></returns>
 		public virtual DataColumn Add()
 		{
+			//FIXME:
 			DataColumn column = new DataColumn("Column" + defaultNameIndex.ToString());
 			CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Add, this);
 			
@@ -97,7 +114,8 @@ namespace System.Data
 		/// </summary>
 		/// <param name="column">The DataColumn to add.</param>
 		public void Add(DataColumn column)
-		{
+		{	
+			//FIXME:
 			if(Contains(column.ColumnName))
 			{
 				throw new DuplicateNameException("A column named " + column.ColumnName + " already belongs to this DataTable.");
@@ -121,6 +139,8 @@ namespace System.Data
 		public virtual DataColumn Add(string columnName)
 		{
 			
+			//FIXME: this wont work.  If the user decides to add a column named
+			//"ColumnXX" where XX is a number these two will conflict.
 			if (columnName == null || columnName == String.Empty)
 			{
 				columnName = "Column" + defaultNameIndex.ToString();
@@ -153,6 +173,8 @@ namespace System.Data
 		{
 			if (columnName == null || columnName == "")
 			{
+				//FIXME: this wont work.  If the user decides to add a column named
+				//"ColumnXX" where XX is a number these two will conflict.
 				columnName = "Column" + defaultNameIndex.ToString();
 				defaultNameIndex++;
 			}
@@ -181,6 +203,7 @@ namespace System.Data
 		/// <returns>The newly created DataColumn.</returns>
 		public virtual DataColumn Add(string columnName, Type type,	string expression)
 		{
+			//FIXME: See Add Logic
 			if (columnName == null || columnName == "")
 			{
 				columnName = "Column" + defaultNameIndex.ToString();
@@ -289,6 +312,7 @@ namespace System.Data
 				}
 			}
 			
+			//TODO: check constraints
 
 			return true;
 		}
@@ -352,7 +376,6 @@ namespace System.Data
 		{
 			if (CollectionChanged != null) 
 			{
-				// Invokes the delegate. 
 				CollectionChanged(this, ccevent);
 			}
 		}
@@ -365,8 +388,9 @@ namespace System.Data
 		{
 			if (CollectionChanged != null) 
 			{
-				// Invokes the delegate. 
-				CollectionChanged(this, ccevent);
+				//FIXME: this is not right
+				//CollectionChanged(this, ccevent);
+				throw new NotImplementedException();
 			}
 		}
 
@@ -376,6 +400,8 @@ namespace System.Data
 		/// <param name="column">The DataColumn to remove.</param>
 		public void Remove(DataColumn column)
 		{
+			//TODO: can remove first with exceptions
+			//and OnChanging Event
 			CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Remove, this);
 			base.List.Remove(column);
 			OnCollectionChanged(e);
@@ -388,6 +414,8 @@ namespace System.Data
 		/// <param name="name">The name of the column to remove.</param>
 		public void Remove(string name)
 		{
+			//TODO: can remove first with exceptions
+			//and OnChanging Event
 			DataColumn column = this[name];
 			CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Remove, this);
 			base.List.Remove(column);
@@ -401,6 +429,8 @@ namespace System.Data
 		/// <param name="index">The index of the column to remove.</param>
 		public void RemoveAt(int index)
 		{
+			//TODO: can remove first with exceptions
+			//and OnChanging Event
 			CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Remove, this);
 			base.List.RemoveAt(index);
 			OnCollectionChanged(e);

+ 35 - 35
mcs/class/System.Data/System.Data/DataRow.cs

@@ -23,15 +23,15 @@ namespace System.Data
 	{
 		#region Fields
 
-		DataTable table;
+		private DataTable _table;
 
-		object[] original;
-		object[] proposed;
-		object[] current;
+		private object[] original;
+		private object[] proposed;
+		private object[] current;
 
-		string[] columnErrors;
-		string rowError;
-		DataRowState rowState;
+		private string[] columnErrors;
+		private string rowError;
+		private DataRowState rowState;
 
 		#endregion
 
@@ -43,13 +43,13 @@ namespace System.Data
 		/// </summary>
 		protected internal DataRow (DataRowBuilder builder)
 		{
-			table = builder.Table;
+			_table = builder.Table;
 
 			original = null; 
 			proposed = null;
-			current = new object[table.Columns.Count];
+			current = new object[_table.Columns.Count];
 
-			columnErrors = new string[table.Columns.Count];
+			columnErrors = new string[_table.Columns.Count];
 			rowError = String.Empty;
 
 			rowState = DataRowState.Unchanged;
@@ -77,7 +77,7 @@ namespace System.Data
 			get { return this[columnName, DataRowVersion.Current]; }
 			[MonoTODO]
 			set {
-				DataColumn column = table.Columns[columnName];
+				DataColumn column = _table.Columns[columnName];
 				if (column == null) 
 					throw new IndexOutOfRangeException ();
 				this[column] = value;
@@ -96,7 +96,7 @@ namespace System.Data
 				bool objIsDBNull = value.Equals(DBNull.Value);
 				if (column == null)
 					throw new ArgumentNullException ();
-				int columnIndex = table.Columns.IndexOf (column);
+				int columnIndex = _table.Columns.IndexOf (column);
 				if (columnIndex == -1)
 					throw new ArgumentException ();
 				if(column.DataType != value.GetType ()) {
@@ -125,7 +125,7 @@ namespace System.Data
 			get { return this[columnIndex, DataRowVersion.Current]; }
 			[MonoTODO]
 			set {
-				DataColumn column = table.Columns[columnIndex]; //FIXME: will throw
+				DataColumn column = _table.Columns[columnIndex]; //FIXME: will throw
 				if (column == null)  
 					throw new IndexOutOfRangeException ();
 				this[column] = value;
@@ -138,7 +138,7 @@ namespace System.Data
 		public object this[string columnName, DataRowVersion version] {
 			[MonoTODO]
 			get {
-				DataColumn column = table.Columns[columnName]; //FIXME: will throw
+				DataColumn column = _table.Columns[columnName]; //FIXME: will throw
 				if (column == null) 
 					throw new IndexOutOfRangeException ();
 				return this[column, version];
@@ -153,7 +153,7 @@ namespace System.Data
 				if (column == null)
 					throw new ArgumentNullException ();	
 
-				int columnIndex = table.Columns.IndexOf (column);
+				int columnIndex = _table.Columns.IndexOf (column);
 
 				if (columnIndex == -1)
 					throw new ArgumentException ();
@@ -185,7 +185,7 @@ namespace System.Data
 		public object this[int columnIndex, DataRowVersion version] {
 			[MonoTODO]
 			get {
-				DataColumn column = table.Columns[columnIndex]; //FIXME: throws
+				DataColumn column = _table.Columns[columnIndex]; //FIXME: throws
 				if (column == null) 
 					throw new IndexOutOfRangeException ();
 				return this[column, version];
@@ -199,25 +199,25 @@ namespace System.Data
 		public object[] ItemArray {
 			get { return current; }
 			set {
-				if (value.Length > table.Columns.Count)
+				if (value.Length > _table.Columns.Count)
 					throw new ArgumentException ();
 				if (rowState == DataRowState.Deleted)
 					throw new DeletedRowInaccessibleException ();
 
 				for (int i = 0; i < value.Length; i += 1)
 				{
-					if (table.Columns[i].ReadOnly && value[i] != this[i])
+					if (_table.Columns[i].ReadOnly && value[i] != this[i])
 						throw new ReadOnlyException ();
 
 					if (value[i] == null)
 					{
-						if (!table.Columns[i].AllowDBNull)
+						if (!_table.Columns[i].AllowDBNull)
 							throw new NoNullAllowedException ();
 						continue;
 					}
 						
 					//FIXME: int strings can be converted to ints
-					if (table.Columns[i].DataType != value[i].GetType())
+					if (_table.Columns[i].DataType != value[i].GetType())
 						throw new InvalidCastException ();
 				}
 
@@ -249,7 +249,7 @@ namespace System.Data
 		/// Gets the DataTable for which this row has a schema.
 		/// </summary>
 		public DataTable Table {
-			get { return table; }
+			get { return _table; }
 		}
 
 		#endregion
@@ -274,7 +274,7 @@ namespace System.Data
 					rowState = DataRowState.Unchanged;
 					break;
 				case DataRowState.Deleted:
-					table.Rows.Remove (this); //FIXME: this should occur in end edit
+					_table.Rows.Remove (this); //FIXME: this should occur in end edit
 					break;
 			}
 
@@ -292,16 +292,16 @@ namespace System.Data
 
 			if (!HasVersion (DataRowVersion.Proposed))
 			{
-				proposed = new object[table.Columns.Count];
-				Array.Copy (current, proposed, table.Columns.Count);
+				proposed = new object[_table.Columns.Count];
+				Array.Copy (current, proposed, _table.Columns.Count);
 			}
 			//TODO: Suspend validation
 
 			//FIXME: this doesn't happen on begin edit
 			if (!HasVersion (DataRowVersion.Original))
 			{
-				original = new object[table.Columns.Count];
-				Array.Copy (current, original, table.Columns.Count);
+				original = new object[_table.Columns.Count];
+				Array.Copy (current, original, _table.Columns.Count);
 			}
 		}
 
@@ -328,7 +328,7 @@ namespace System.Data
 		public void ClearErrors () 
 		{
 			rowError = String.Empty;
-			columnErrors = new String[table.Columns.Count];
+			columnErrors = new String[_table.Columns.Count];
 		}
 
 		/// <summary>
@@ -354,7 +354,7 @@ namespace System.Data
 			{
 				rowState = DataRowState.Modified;
 				//TODO: Validate Constraints, Events
-				Array.Copy (proposed, current, table.Columns.Count);
+				Array.Copy (proposed, current, _table.Columns.Count);
 				proposed = null;
 			}
 		}
@@ -403,7 +403,7 @@ namespace System.Data
 		/// </summary>
 		public string GetColumnError (DataColumn column) 
 		{
-			return GetColumnError (table.Columns.IndexOf(column));
+			return GetColumnError (_table.Columns.IndexOf(column));
 		}
 
 		/// <summary>
@@ -422,7 +422,7 @@ namespace System.Data
 		/// </summary>
 		public string GetColumnError (string columnName) 
 		{
-			return GetColumnError (table.Columns.IndexOf(columnName));
+			return GetColumnError (_table.Columns.IndexOf(columnName));
 		}
 
 		/// <summary>
@@ -435,7 +435,7 @@ namespace System.Data
 			for (int i = 0; i < columnErrors.Length; i += 1)
 			{
 				if (columnErrors[i] != String.Empty)
-					dataColumns.Add (table.Columns[i]);
+					dataColumns.Add (_table.Columns[i]);
 			}
 
 			return (DataColumn[])(dataColumns.ToArray ());
@@ -581,12 +581,12 @@ namespace System.Data
 			// was last called.  We have no "original" to go back to.
 			if (original != null)
 			{
-				Array.Copy (original, current, table.Columns.Count);
+				Array.Copy (original, current, _table.Columns.Count);
 				CancelEdit ();
 				switch (rowState)
 				{
 					case DataRowState.Added:
-						table.Rows.Remove (this);
+						_table.Rows.Remove (this);
 						break;
 					case DataRowState.Modified:
 						rowState = DataRowState.Unchanged;
@@ -603,7 +603,7 @@ namespace System.Data
 		/// </summary>
 		public void SetColumnError (DataColumn column, string error) 
 		{
-			SetColumnError (table.Columns.IndexOf (column), error);
+			SetColumnError (_table.Columns.IndexOf (column), error);
 		}
 
 		/// <summary>
@@ -621,7 +621,7 @@ namespace System.Data
 		/// </summary>
 		public void SetColumnError (string columnName, string error) 
 		{
-			SetColumnError (table.Columns.IndexOf (columnName), error);
+			SetColumnError (_table.Columns.IndexOf (columnName), error);
 		}
 
 		/// <summary>

+ 2 - 2
mcs/class/System.Data/System.Data/DataRowBuilder.cs

@@ -23,7 +23,7 @@ namespace System.Data
 	{
 		#region Fields
 		
-		DataTable table;
+		private DataTable table;
 
 		#endregion
 
@@ -33,7 +33,7 @@ namespace System.Data
 		// DataTable and two Int32.  For consistency, this
 		// class will also take those arguments.
 
-		protected internal DataRowBuilder (DataTable table, int x, int y)
+		protected internal DataRowBuilder (DataTable table, Int32 x, Int32 y)
 		{
 			this.table = table;
 		}

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

@@ -52,6 +52,8 @@ namespace System.Data
 		/// </summary>
 		public void Add (DataRow row) 
 		{
+			//TODO: AutoIncrement
+			//TODO: validation
 			list.Add (row);
 		}
 

+ 120 - 70
mcs/class/System.Data/System.Data/DataTable.cs

@@ -289,16 +289,41 @@ namespace System.Data
 		/// Gets or sets an array of columns that function as 
 		/// primary keys for the data table.
 		/// </summary>
-		[MonoTODO]
 		public DataColumn[] PrimaryKey
 		{
 			get {
-				//TODO: compute PrimaryKey
-				if (null == _primaryKey) return new DataColumn[]{};
-				return _primaryKey;
+				UniqueConstraint uc = UniqueConstraint.GetPrimaryKeyConstraint( Constraints);
+				if (null == uc) return new DataColumn[] {};
+				return uc.Columns;
 			}
 			set {
-				_primaryKey = value;
+
+				//YUK: msft removes a previous unique constraint if it is flagged as a pk  
+				//when a new pk is set 
+
+				//clear Primary Key if value == null
+				if (null == value)
+				{
+					UniqueConstraint.SetAsPrimaryKey(this.Constraints, null);
+					return;
+				}
+			
+
+				//Does constraint exist for these columns
+				UniqueConstraint uc = UniqueConstraint.GetUniqueConstraintForColumnSet(
+						this.Constraints, (DataColumn[]) value);
+
+				//if constraint doesn't exist for columns
+				//create new unique primary key constraint
+				if (null == uc)
+				{
+					uc = new UniqueConstraint( (DataColumn[]) value, true);
+				}
+				else //set existing constraint as the new primary key
+				{
+					UniqueConstraint.SetAsPrimaryKey(this.Constraints, uc);
+				}
+				
 			}
 		}
 
@@ -557,156 +582,178 @@ namespace System.Data
 	
 
 		/// <summary>
-		/// Raises the ColumnChanged event.
+		/// Rolls back all changes that have been made to the 
+		/// table since it was loaded, or the last time AcceptChanges
+		///  was called.
 		/// </summary>
+		
 		[MonoTODO]
-		protected virtual void OnColumnChanged(DataColumnChangeEventArgs e)
+		public void RejectChanges()
 		{
 		}
 
 		/// <summary>
-		/// Raises the ColumnChanging event.
+		/// Resets the DataTable to its original state.
 		/// </summary>
 		
 		[MonoTODO]
-		protected virtual void OnColumnChanging(DataColumnChangeEventArgs e)
+		public virtual void Reset()
 		{
 		}
 
 		/// <summary>
-		/// Raises the PropertyChanging event.
+		/// Gets an array of all DataRow objects.
 		/// </summary>
 		
 		[MonoTODO]
-		protected internal virtual void OnPropertyChanging(PropertyChangedEventArgs pcevent)
+		public DataRow[] Select()
 		{
+			//FIXME:
+			DataRow[] dataRows = {null};
+			return dataRows;
 		}
 
 		/// <summary>
-		/// Notifies the DataTable that a DataColumn is being removed.
+		/// Gets an array of all DataRow objects that match 
+		/// the filter criteria in order of primary key (or 
+		/// lacking one, order of addition.)
 		/// </summary>
 		
 		[MonoTODO]
-		protected internal virtual void OnRemoveColumn(DataColumn column)
+		public DataRow[] Select(string filterExpression)
 		{
+			DataRow[] dataRows = {null};
+			return dataRows;
 		}
 
 		/// <summary>
-		/// Raises the RowChanged event.
+		/// Gets an array of all DataRow objects that 
+		/// match the filter criteria, in the the 
+		/// specified sort order.
 		/// </summary>
-		
 		[MonoTODO]
-		protected virtual void OnRowChanged(DataRowChangeEventArgs e)
+		public DataRow[] Select(string filterExpression, string sort)
 		{
+			DataRow[] dataRows = {null};
+			return dataRows;
 		}
 
 		/// <summary>
-		/// Raises the RowChanging event.
+		/// Gets an array of all DataRow objects that match
+		/// the filter in the order of the sort, that match 
+		/// the specified state.
 		/// </summary>
-		
 		[MonoTODO]
-		protected virtual void OnRowChanging(DataRowChangeEventArgs e)
+		public DataRow[] Select(string filterExpression, string sort, DataViewRowState recordStates)
 		{
+			DataRow[] dataRows = {null};
+			return dataRows;
 		}
 
 		/// <summary>
-		/// Raises the RowDeleted event.
+		/// Gets the TableName and DisplayExpression, if 
+		/// there is one as a concatenated string.
 		/// </summary>
-		
-		[MonoTODO]
-		protected virtual void OnRowDeleted(DataRowChangeEventArgs e)
+		public override string ToString()
 		{
+			//LAMESPEC: spec says concat the two. impl puts a 
+			//plus sign infront of DisplayExpression
+			return TableName + " " + DisplayExpression;
 		}
 
+		
+		#region Events /////////////////
+		
 		/// <summary>
-		/// Raises the RowDeleting event.
+		/// Raises the ColumnChanged event.
 		/// </summary>
-		
-		[MonoTODO]
-		protected virtual void OnRowDeleting(DataRowChangeEventArgs e)
+		protected virtual void OnColumnChanged(DataColumnChangeEventArgs e)
 		{
+			if (null != ColumnChanged)
+			{
+				ColumnChanged(this, e);
+			}
 		}
 
 		/// <summary>
-		/// Rolls back all changes that have been made to the 
-		/// table since it was loaded, or the last time AcceptChanges
-		///  was called.
+		/// Raises the ColumnChanging event.
 		/// </summary>
-		
-		[MonoTODO]
-		public void RejectChanges()
+		protected virtual void OnColumnChanging(DataColumnChangeEventArgs e)
 		{
+			if (null != ColumnChanging)
+			{
+				ColumnChanging(this, e);
+			}
 		}
 
 		/// <summary>
-		/// Resets the DataTable to its original state.
+		/// Raises the PropertyChanging event.
 		/// </summary>
-		
 		[MonoTODO]
-		public virtual void Reset()
+		protected internal virtual void OnPropertyChanging(PropertyChangedEventArgs pcevent)
 		{
+//			if (null != PropertyChanging)
+//			{
+//				PropertyChanging(this, e);
+//			}
 		}
 
 		/// <summary>
-		/// Gets an array of all DataRow objects.
+		/// Notifies the DataTable that a DataColumn is being removed.
 		/// </summary>
-		
 		[MonoTODO]
-		public DataRow[] Select()
+		protected internal virtual void OnRemoveColumn(DataColumn column)
 		{
-			//FIXME:
-			DataRow[] dataRows = {null};
-			return dataRows;
+//			if (null != RemoveColumn)
+//			{
+//				RemoveColumn(this, e);
+//			}
 		}
 
 		/// <summary>
-		/// Gets an array of all DataRow objects that match 
-		/// the filter criteria in order of primary key (or 
-		/// lacking one, order of addition.)
+		/// Raises the RowChanged event.
 		/// </summary>
 		
-		[MonoTODO]
-		public DataRow[] Select(string filterExpression)
+		protected virtual void OnRowChanged(DataRowChangeEventArgs e)
 		{
-			DataRow[] dataRows = {null};
-			return dataRows;
+			if (null != RowChanged)
+			{
+				RowChanged(this, e);
+			}
 		}
 
 		/// <summary>
-		/// Gets an array of all DataRow objects that 
-		/// match the filter criteria, in the the 
-		/// specified sort order.
+		/// Raises the RowChanging event.
 		/// </summary>
 		
-		[MonoTODO]
-		public DataRow[] Select(string filterExpression, string sort)
+		protected virtual void OnRowChanging(DataRowChangeEventArgs e)
 		{
-			DataRow[] dataRows = {null};
-			return dataRows;
+			if (null != RowChanging)
+			{
+				RowChanging(this, e);
+			}
 		}
 
 		/// <summary>
-		/// Gets an array of all DataRow objects that match
-		/// the filter in the order of the sort, that match 
-		/// the specified state.
+		/// Raises the RowDeleted event.
 		/// </summary>
-		
-		[MonoTODO]
-		public DataRow[] Select(string filterExpression, string sort, DataViewRowState recordStates)
+		protected virtual void OnRowDeleted(DataRowChangeEventArgs e)
 		{
-			DataRow[] dataRows = {null};
-			return dataRows;
+			if (null != RowDeleted)
+			{
+				RowDeleted(this, e);
+			}
 		}
 
 		/// <summary>
-		/// Gets the TableName and DisplayExpression, if 
-		/// there is one as a concatenated string.
+		/// Raises the RowDeleting event.
 		/// </summary>
-		
-		[MonoTODO]
-		public override string ToString()
+		protected virtual void OnRowDeleting(DataRowChangeEventArgs e)
 		{
-			return "";
+			if (null != RowDeleting)
+			{
+				RowDeleting(this, e);
+			}
 		}
 
 		/// <summary>
@@ -746,5 +793,8 @@ namespace System.Data
 		/// </summary>
 		
 		public event DataRowChangeEventHandler RowDeleting;
+		
+		#endregion //Events
 	}
+
 }

+ 50 - 7
mcs/class/System.Data/System.Data/UniqueConstraint.cs

@@ -124,7 +124,7 @@ namespace System.Data
 			base.ConstraintName = name;
 
 			//set unique
-			_setColumnsUnique (columns);
+			if (columns.Length == 1) columns[0].Unique = true;
 
 			//keep reference
 			_dataColumns = columns;
@@ -137,12 +137,6 @@ namespace System.Data
 		#endregion // Constructors
 
 		#region Helpers
-		private void _setColumnsUnique(DataColumn [] columns) {
-			if (null == columns) return;
-			foreach (DataColumn col in columns) {
-				col.Unique = true;
-			}
-		}
 		
 		private void _validateColumns(DataColumn [] columns)
 		{
@@ -193,9 +187,50 @@ namespace System.Data
 			
 		}
 
+		internal static void SetAsPrimaryKey(ConstraintCollection collection, UniqueConstraint newPrimaryKey)
+		{
+			//not null
+			if (null == collection) throw new ArgumentNullException("ConstraintCollection can't be null.");
+			
+			//make sure newPrimaryKey belongs to the collection parm unless it is null
+			if (  collection.IndexOf(newPrimaryKey) < 1 && (null != newPrimaryKey) ) 
+				throw new ArgumentException("newPrimaryKey must belong to collection.");
+			
+			//Get existing pk
+			UniqueConstraint uc = GetPrimaryKeyConstraint(collection);
+			
+			//clear existing
+			if (null != uc) uc._isPrimaryKey = false;
+
+			//set new key
+			if (null != newPrimaryKey) newPrimaryKey._isPrimaryKey = true;
+			
+			
+		}
+
+		internal static UniqueConstraint GetPrimaryKeyConstraint(ConstraintCollection collection)
+		{
+			if (null == collection) throw new ArgumentNullException("Collection can't be null.");
+
+			UniqueConstraint uc;
+			IEnumerator enumer = collection.GetEnumerator();
+			while (enumer.MoveNext())
+			{
+				uc = enumer.Current as UniqueConstraint;
+				if (null == uc) continue;
+				
+				if (uc.IsPrimaryKey) return uc;	
+			}
+
+			//if we got here there was no pk
+			return null;
+			
+		}
+
 		internal static UniqueConstraint GetUniqueConstraintForColumnSet(ConstraintCollection collection,
 				DataColumn[] columns)
 		{
+			if (null == collection) throw new ArgumentNullException("Collection can't be null.");
 			if (null == columns ) return null;
 			
 			UniqueConstraint uniqueConstraint;
@@ -269,6 +304,14 @@ namespace System.Data
 			UniqueConstraint uc = UniqueConstraint.GetUniqueConstraintForColumnSet(collection, this.Columns);	
 			if (null != uc) throw new ArgumentException("Unique constraint already exists for these" +
 					" columns. Existing ConstraintName is " + uc.ConstraintName);
+
+			//Allow only one primary key
+			if (this.IsPrimaryKey)
+			{
+				uc = GetPrimaryKeyConstraint(collection);
+				if (null != uc) uc._isPrimaryKey = false;
+
+			}
 					
 			AssertConstraint();
 		}

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

@@ -1,3 +1,10 @@
+2002-09-04  Franklin Wise <[email protected]>
+	
+	* New Files: 
+		System.Data\DataRowCollectionTest.cs
+		System.Data\DataRowTest.cs
+		System.Data\DataColumnCollectionTest.cs
+		
 2002-08-20  Franklin Wise <[email protected]>
 	
 	* NewFile: System.Data\DataTableTest.cs

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

@@ -27,6 +27,9 @@ namespace MonoTests.System.Data
 				suite.AddTest (new TestSuite (typeof (ConstraintCollectionTest)));
 				suite.AddTest (new TestSuite (typeof (ForeignKeyConstraintTest)));
 				suite.AddTest (new TestSuite (typeof (DataTableTest)));
+				suite.AddTest (new TestSuite (typeof (DataRowCollectionTest)));
+				suite.AddTest (new TestSuite (typeof (DataRowTest)));
+				suite.AddTest (new TestSuite (typeof (DataColumnCollectionTest)));
 				return suite;
 			}
 		}

+ 46 - 0
mcs/class/System.Data/Test/System.Data/DataColumnCollectionTest.cs

@@ -0,0 +1,46 @@
+// DataColumnCollectionTest.cs - NUnit Test Cases for System.Data.DataColumnCollection
+//
+// Author:
+//   Franklin Wise <[email protected]>
+//
+// (C) Copyright 2002 Franklin Wise
+//
+
+using NUnit.Framework;
+using System;
+using System.Data;
+
+namespace MonoTests.System.Data
+{
+	public class DataColumnCollectionTest : TestCase
+	{
+		public DataColumnCollectionTest () : base ("MonoTest.System.Data.DataColumnCollectionTest") {}
+		public DataColumnCollectionTest (string name) : base (name) {}
+
+		private DataTable _tbl;
+
+		protected override void SetUp () 
+		{
+			_tbl = new DataTable();
+		}
+
+		protected override void TearDown() {}
+
+		public static ITest Suite {
+			get { 
+				return new TestSuite (typeof (DataColumnCollectionTest)); 
+			}
+		}
+
+		//TODO
+		public void TestAddValidationExceptions()
+		{
+			
+			//Set DefaultValue and AutoIncr == true
+			//And get an exception
+		}
+
+
+		
+	}
+}

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

@@ -1,8 +1,10 @@
 // DataColumnTest.cs - NUnit Test Cases for System.Data.DataColumn
 //
 // Author:
+//   Franklin Wise <[email protected]>
 //   Rodrigo Moya <[email protected]>
 //
+// (C) Copyright 2002 Franklin Wise
 // (C) Copyright 2002 Rodrigo Moya
 //
 
@@ -17,7 +19,12 @@ namespace MonoTests.System.Data
 		public DataColumnTest () : base ("System.Data.DataColumn") {}
 		public DataColumnTest (string name) : base (name) {}
 
-		protected override void SetUp () {}
+		private DataTable _tbl;
+
+		protected override void SetUp () 
+		{
+			_tbl = new DataTable();
+		}
 
 		protected override void TearDown() {}
 
@@ -27,6 +34,158 @@ namespace MonoTests.System.Data
 			}
 		}
 
-		public void TestBlank()	{} //Remove me when we add some tests
+		public void TestCtor()	
+		{
+			string colName = "ColName";
+			DataColumn col = new DataColumn();
+			
+			//These should all ctor without an exception
+			col = new DataColumn(colName);
+			col = new DataColumn(colName,typeof(int));
+			col = new DataColumn(colName,typeof(int),null);
+			col = new DataColumn(colName,typeof(int),null,MappingType.Attribute);
+
+			//DataType Null
+			try
+			{
+				col = new DataColumn(colName, null);
+				Assertion.Fail("Failed to throw ArgumentNullException.");
+			}
+			catch (ArgumentNullException){}
+			catch (AssertionFailedError exc) {throw  exc;}
+			catch (Exception exc)
+			{
+				Assertion.Fail("DataColumnNull. Wrong exception type.");
+			}
+
+		}
+
+
+		//Wont Pass
+		public void TestAllowDBNull()
+		{
+			DataColumn col = new DataColumn("NullCheck",typeof(int));
+			_tbl.Columns.Add(col);
+			col.AllowDBNull = true;
+			_tbl.Rows.Add(_tbl.NewRow());
+			_tbl.Rows[0]["NullCheck"] = DBNull.Value;
+
+			try
+			{
+				col.AllowDBNull = false;
+				Assertion.Fail("Failed to throw DataException.");
+			}
+			catch (DataException){}
+			catch (AssertionFailedError exc) {throw  exc;}
+			catch (Exception exc)
+			{
+				Assertion.Fail("DataColumnNull. Wrong exception type.");
+			}
+			
+
+
+		}
+
+
+		public void TestAutoIncrement()
+		{
+			DataColumn col = new DataColumn("Auto",typeof(string));
+			col.AutoIncrement = true;
+			
+			//Check for Correct Default Values
+			Assertion.AssertEquals("Seed default", (long)0, col.AutoIncrementSeed);
+			Assertion.AssertEquals("Step default", (long)1, col.AutoIncrementStep);
+
+			//Check for auto type convert
+			Assertion.Assert("AutoInc type convert failed." ,col.DataType == typeof (int));
+
+		}
+
+		public void TestAutoIncrementExceptions()
+		{
+			DataColumn col = new DataColumn();
+
+			col.Expression = "SomeExpression";
+
+			//if computed column exception is thrown
+			try 
+			{
+				col.AutoIncrement = true;
+				Assertion.Fail("Failed to throw ArgumentException");
+			}
+			catch (ArgumentException){}
+			catch (AssertionFailedError exc) {throw  exc;}
+			catch (Exception exc)
+			{
+				Assertion.Fail("ExprAutoInc. Wrong exception type.");
+			}
+
+
+		}
+
+		public void TestCaption()
+		{
+			DataColumn col = new DataColumn("ColName");
+			//Caption not set at this point
+			Assertion.AssertEquals("Caption Should Equal Col Name", col.ColumnName, col.Caption);
+
+			//Set caption
+			col.Caption = "MyCaption";
+			Assertion.AssertEquals("Caption should equal caption.", "MyCaption", col.Caption);
+
+			//Clear caption
+			col.Caption = null;
+			Assertion.AssertEquals("Caption Should Equal Col Name after clear", col.ColumnName, col.Caption);
+			
+		}
+
+		public void TestForColumnNameException()
+		{
+			DataColumn col = new DataColumn();
+			DataColumn col2 = new DataColumn();
+			
+			_tbl.Columns.Add(col);
+			_tbl.Columns.Add(col2);
+
+			col.ColumnName = "abc";
+			
+			//Duplicate name exception
+			try
+			{
+				col2.ColumnName = "aBc";
+				Assertion.Fail("Failed to throw duplicate name exception.");
+			}
+			catch (DuplicateNameException){}
+			catch (AssertionFailedError exc) {throw  exc;}
+			catch (Exception exc)
+			{
+				Assertion.Fail("DNE: Wrong exception type. " + exc.ToString());
+			}
+
+			//null name exception
+
+			try
+			{	
+				col.ColumnName = null;
+				Assertion.Fail("Failed to throw ArgumentException.");
+			}
+			catch (ArgumentException){}
+			catch (AssertionFailedError exc) {throw  exc;}
+			catch (Exception exc)
+			{
+				Assertion.Fail("AE: Wrong exception type. " + exc.ToString());
+			}
+			
+		}
+
+		public void TestSetDataType()
+		{
+			//test for DataAlready exists and change the datatype
+			
+			//supported datatype
+
+			//AutoInc column dataType supported
+
+		}
 	}
 }

+ 56 - 0
mcs/class/System.Data/Test/System.Data/DataRowCollectionTest.cs

@@ -0,0 +1,56 @@
+// DataRowCollectionTest.cs - NUnit Test Cases for System.DataRowCollection
+//
+// Franklin Wise ([email protected])
+//
+// (C) Copyright 2002 Franklin Wise
+// 
+
+
+using NUnit.Framework;
+using System;
+using System.Data;
+
+namespace MonoTests.System.Data
+{
+
+	public class DataRowCollectionTest : TestCase 
+	{
+	
+		public DataRowCollectionTest() : base ("MonoTests.System.Data.DataRowCollectionTest") {}
+		public DataRowCollectionTest(string name) : base(name) {}
+
+		private DataTable _tbl;	
+
+		protected override void SetUp()
+		{
+			_tbl = new DataTable();
+		}
+
+		protected override void TearDown() {}
+
+		public static ITest Suite 
+		{
+			get 
+			{ 
+				return new TestSuite(typeof(DataRowCollectionTest)); 
+			}
+		}
+
+		//FINISHME
+		public void TestAutoIncrement()
+		{
+			DataColumn col = new DataColumn();
+			col.AutoIncrement = true;
+			col.AutoIncrementSeed = 0;
+			col.AutoIncrementStep = 1;
+			
+			_tbl.Columns.Add(col);
+			_tbl.Rows.Add(_tbl.NewRow());
+
+			//Assertion.AssertEquals("Inc 0" , 0, Convert.ToInt32(_tbl.Rows[0]["Auto"] ));
+				
+			_tbl.Rows.Add(_tbl.NewRow());
+			//Assertion.AssertEquals("Inc 1" , 1, Convert.ToInt32(_tbl.Rows[0]["Auto"] ));
+		}
+	}
+}

+ 42 - 0
mcs/class/System.Data/Test/System.Data/DataRowTest.cs

@@ -0,0 +1,42 @@
+// DataRowTest.cs - NUnit Test Cases for System.DataRow
+//
+// Franklin Wise ([email protected])
+//
+// (C) Copyright 2002 Franklin Wise
+// 
+
+
+using NUnit.Framework;
+using System;
+using System.Data;
+
+namespace MonoTests.System.Data
+{
+
+	public class DataRowTest : TestCase 
+	{
+	
+		public DataRowTest() : base ("MonoTests.System.Data.DataRowTest") {}
+		public DataRowTest(string name) : base(name) {}
+
+		private DataTable _tbl;	
+
+		protected override void SetUp()
+		{
+			_tbl = new DataTable();
+		}
+
+		protected override void TearDown() {}
+
+		public static ITest Suite 
+		{
+			get 
+			{ 
+				return new TestSuite(typeof(DataRowTest)); 
+			}
+		}
+
+		//Remove when real tests are added.
+		public void TestRemoveMe(){}
+	}
+}

+ 28 - 15
mcs/class/System.Data/Test/System.Data/DataTableTest.cs

@@ -35,24 +35,37 @@ namespace MonoTests.System.Data
 			DataTable dt = new DataTable();
 
 			Assertion.AssertEquals("CaseSensitive must be false." ,false,dt.CaseSensitive);
-			Assertion.Assert(dt.Columns != null);
+			Assertion.Assert("Col",dt.Columns != null);
 			//Assertion.Assert(dt.ChildRelations != null);
-			Assertion.Assert(dt.Constraints != null);
-			Assertion.Assert(dt.DataSet == null); 
-			Assertion.Assert(dt.DefaultView != null);
-			Assertion.Assert(dt.DisplayExpression == "");
-			Assertion.Assert(dt.ExtendedProperties != null);
-			Assertion.Assert(dt.HasErrors == false);
-			Assertion.Assert(dt.Locale != null);
-			Assertion.Assert(dt.MinimumCapacity == 50); //LAMESPEC:
-			Assertion.Assert(dt.Namespace == "");
+			Assertion.Assert("Const", dt.Constraints != null);
+			Assertion.Assert("ds", dt.DataSet == null); 
+			Assertion.Assert("dv", dt.DefaultView != null);
+			Assertion.Assert("de", dt.DisplayExpression == "");
+			Assertion.Assert("ep", dt.ExtendedProperties != null);
+			Assertion.Assert("he", dt.HasErrors == false);
+			Assertion.Assert("lc", dt.Locale != null);
+			Assertion.Assert("mc", dt.MinimumCapacity == 50); //LAMESPEC:
+			Assertion.Assert("ns", dt.Namespace == "");
 			//Assertion.Assert(dt.ParentRelations != null);
-			Assertion.Assert(dt.Prefix == "");
-			Assertion.Assert(dt.PrimaryKey != null);
-			Assertion.Assert(dt.Rows != null);
-			Assertion.Assert(dt.Site == null);
-			Assertion.Assert(dt.TableName == "");
+			Assertion.Assert("pf", dt.Prefix == "");
+			Assertion.Assert("pk", dt.PrimaryKey != null);
+			Assertion.Assert("rows", dt.Rows != null);
+			Assertion.Assert("Site", dt.Site == null);
+			Assertion.Assert("tname", dt.TableName == "");
 			
 		}
+
+		public void TestToString()
+		{
+			DataTable dt = new DataTable();
+			dt.Columns.Add("Col1",typeof(int));
+			
+			dt.TableName = "Myzable";
+			dt.DisplayExpression = "Col1";
+			
+			
+			string cmpr = dt.TableName + " " + dt.DisplayExpression;
+			Assertion.AssertEquals(cmpr,dt.ToString());
+		}
 	}
 }