*** empty log message ***
authorFranklin Wise <fwise@mono-cvs.ximian.com>
Thu, 15 Aug 2002 20:31:01 +0000 (20:31 -0000)
committerFranklin Wise <fwise@mono-cvs.ximian.com>
Thu, 15 Aug 2002 20:31:01 +0000 (20:31 -0000)
svn path=/trunk/mcs/; revision=6653

12 files changed:
mcs/class/System.Data/ChangeLog
mcs/class/System.Data/System.Data/Constraint.cs
mcs/class/System.Data/System.Data/ConstraintCollection.cs
mcs/class/System.Data/System.Data/DataColumn.cs
mcs/class/System.Data/System.Data/ForeignKeyConstraint.cs
mcs/class/System.Data/System.Data/UniqueConstraint.cs
mcs/class/System.Data/Test/ChangeLog
mcs/class/System.Data/Test/System.Data/AllTests.cs
mcs/class/System.Data/Test/System.Data/ConstraintCollectionTest.cs
mcs/class/System.Data/Test/System.Data/ConstraintTest.cs
mcs/class/System.Data/Test/System.Data/ForeignKeyConstraintTest.cs [new file with mode: 0644]
mcs/class/System.Data/Test/System.Data/UniqueConstraintTest.cs

index dd87bc02722c17e5d084d08c3ccecf6faab7aecd..d02e77653d554cc2aa9cb0d138e557e936fb53c8 100644 (file)
@@ -1,3 +1,19 @@
+2002-08-15  Franklin Wise <gracenote@earthlink.net>
+       
+       * System.Data/Constraint.cs: Added helper virtual functions
+
+       * System.Data/ConstraintCollection.cs: Improved constraint removal,
+       validation.  Removed specific knowledge of subclasses of 
+       Constraint.
+
+       * System.Data/DataColumn.cs: Added static helper function to compare
+       if two DataColumn arrays are the same.
+
+       * System.Data/ForeignKeyConstraint.cs: Continued to flush out.
+
+       * System.Data/UniqueConstraint.cs: Implemented.  Still some constraint
+       validation to do.
+       
 2002-08-13  Franklin Wise <gracenote@earthlink.net>
 
        * System.Data/DataRow.cs: Added several fixme tags.
index 51229e4d6b60137a357eeb5c38518b5dcfda5111..0dac5037eb70880e5102e806429a374074f51851 100644 (file)
@@ -27,7 +27,12 @@ namespace System.Data
                internal event DelegateConstraintNameChange 
                                        BeforeConstraintNameChange;
 
-               private string _name = null;
+               //if constraintName is not set then a name is 
+               //created when it is added to
+               //the ConstraintCollection
+               //it can not be set to null, empty or duplicate
+               //once it has been added to the collection
+               private string _constraintName = null;
                private PropertyCollection _properties = null;
 
                //Used for membership checking
@@ -40,7 +45,7 @@ namespace System.Data
 
                public virtual string ConstraintName {
                        get{
-                               return "" + _name;
+                               return "" + _constraintName;
                        } 
 
                        set{
@@ -49,7 +54,7 @@ namespace System.Data
                                //means we should let the ConstraintCollection
                                //handle exceptions when this value changes
                                _onConstraintNameChange(value);
-                               _name = value;
+                               _constraintName = value;
                        }
                }
 
@@ -68,7 +73,7 @@ namespace System.Data
                /// </summary>
                public override string ToString() 
                {
-                       return "" + _name;
+                       return "" + _constraintName;
                }
 
                internal ConstraintCollection ConstraintCollection {
@@ -81,7 +86,6 @@ namespace System.Data
                }
                
 
-
                private void _onConstraintNameChange(string newName)
                {
                        if (null != BeforeConstraintNameChange)
@@ -90,5 +94,20 @@ namespace System.Data
                        }
                }
 
+               //call once before adding a constraint to a collection
+               //will throw an exception to prevent the add if a rule is broken
+               internal protected abstract void AddToConstraintCollectionSetup(
+                               ConstraintCollection collection);
+                                       
+               //call once before removing a constraint to a collection
+               //can throw an exception to prevent the removal
+               internal protected abstract void RemoveFromConstraintCollectionCleanup( 
+                               ConstraintCollection collection);
+
+
+               //Call to Validate the constraint
+               //Will throw if constraint is violated
+               internal abstract void AssertConstraint();
+               
        }
 }
index 5b953081bc2bd5a42b807fd9de9daf367c9bbfb2..424ed2cf1ee0e3e8189c9ecb8844c26a1a240ea6 100644 (file)
@@ -18,7 +18,7 @@ namespace System.Data
 {
        [Serializable]
        internal delegate void DelegateValidateRemoveConstraint(ConstraintCollection sender,
-                       Constraint constraintToRemove, ref bool cancel);
+                       Constraint constraintToRemove, ref bool fail,ref string failReason);
        
        /// <summary>
        /// hold collection of constraints for data table
@@ -37,7 +37,8 @@ namespace System.Data
 
                public virtual Constraint this[string name] {
                        get {
-                               int index = IndexOf(name);
+                               //If the name is not found we just return null
+                               int index = IndexOf(name); //case insensitive
                                if (-1 == index) return null;
                                return this[index];
                        }
@@ -45,6 +46,8 @@ namespace System.Data
                
                public virtual Constraint this[int index] {
                        get {
+                               if (index < 0 || index >= List.Count)
+                                       throw new IndexOutOfRangeException();
                                return (Constraint)List[index];
                        }
                }
@@ -118,10 +121,16 @@ namespace System.Data
                        if (null != constraint.ConstraintCollection) 
                                throw new ArgumentException("Constraint already belongs to another collection.");
                        
-                       //check for duplicate
+                       //check for duplicate name
                        if (_isDuplicateConstraintName(constraint.ConstraintName,null)  )
                                throw new DuplicateNameException("Constraint name already exists.");
                
+                       //Allow constraint to run validation rules and setup 
+                       constraint.AddToConstraintCollectionSetup(this); //may throw if it can't setup
+
+                       //Run Constraint to check existing data in table
+                       constraint.AssertConstraint();
+
                        //if name is null or empty give it a name
                        if (constraint.ConstraintName == null || 
                                constraint.ConstraintName == "" ) 
@@ -195,13 +204,14 @@ namespace System.Data
                        //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 (?).
+                       //TODO: I may want to change how this is done
+                       //maybe put a CanRemove on the Constraint class
+                       //and have the Constraint fire this event
+
                        //discover if there is a related ForeignKey
-                       return _canRemoveConstraint(constraint);
+                       string failReason ="";
+                       return _canRemoveConstraint(constraint, ref failReason);
                        
                }
 
@@ -270,6 +280,16 @@ namespace System.Data
                        //not null
                        if (null == constraint) throw new ArgumentNullException();
 
+                       string failReason = "";
+                       if (! _canRemoveConstraint(constraint, ref failReason) )
+                       {
+                               if (failReason != null || failReason != "")     
+                                       throw new ArgumentException(failReason);
+                               else
+                                       throw new ArgumentException("Can't remove constraint.");                
+                       }
+                               
+                       constraint.RemoveFromConstraintCollectionCleanup(this);
                        List.Remove(constraint);
                        OnCollectionChanged( new CollectionChangeEventArgs(CollectionChangeAction.Remove,this));
                }
@@ -289,6 +309,7 @@ namespace System.Data
                                throw new IndexOutOfRangeException("Index out of range, index = " 
                                                + index.ToString() + ".");
        
+                       this[index].RemoveFromConstraintCollectionCleanup(this);
                        List.RemoveAt(index);
                        OnCollectionChanged( new CollectionChangeEventArgs(CollectionChangeAction.Remove,this));
                }
@@ -308,13 +329,15 @@ namespace System.Data
                        }
                }
 
-               private bool _canRemoveConstraint(Constraint constraint )
+               private bool _canRemoveConstraint(Constraint constraint, ref string failReason )
                {
                        bool cancel = false;
+                       string tmp = "";
                        if (null != ValidateRemoveConstraint)
                        {
-                               ValidateRemoveConstraint(this, constraint, ref cancel);
+                               ValidateRemoveConstraint(this, constraint, ref cancel, ref tmp);
                        }
+                       failReason = tmp;
                        return !cancel;
                }
        }
index 51bbda4da2bd3199a0594a41a355e9458bffa271..0743e70be7fbf353af371fe5583b1f99fdb1ec55 100644 (file)
@@ -16,11 +16,26 @@ using System.ComponentModel;
 
 namespace System.Data
 {
+       internal delegate void DelegateColumnValueChange(DataColumn column,
+                       DataRow row, object proposedValue);
+
+       
        /// <summary>
        /// Summary description for DataColumn.
        /// </summary>
        public class DataColumn : MarshalByValueComponent
        {               
+               #region Events
+               [MonoTODO]
+               //used for constraint validation
+               //if an exception is fired during this event the change should be canceled
+               internal event DelegateColumnValueChange ValidateColumnValueChange;
+
+               //used for FK Constraint Cascading rules
+               internal event DelegateColumnValueChange ColumnValueChanging;
+               #endregion //Events
+
+               
                #region Fields
 
                private bool allowDBNull = true;
@@ -329,6 +344,31 @@ namespace System.Data
                        // and DataColumnCollection
                }
 
+               
+               // Returns true if all the same collumns are in columnSet and compareSet
+               internal static bool AreColumnSetsTheSame(DataColumn[] columnSet, DataColumn[] compareSet)
+               {
+                       if (null == columnSet && null == compareSet) return true;
+                       if (null == columnSet || null == compareSet) return false;
+
+                       if (columnSet.Length != compareSet.Length) return false;
+                       
+                       foreach (DataColumn col in columnSet)
+                       {
+                               bool matchFound = false;
+                               foreach (DataColumn compare in compareSet)
+                               {
+                                       if (col == compare)
+                                       {
+                                               matchFound = true;                                      
+                                       }
+                               }
+                               if (! matchFound) return false;
+                       }
+                       
+                       return true;
+               }
+               
                #endregion // Methods
 
        }
index 756d6ef10a5897ee49e11865f3768e447d3c41c2..54bfde17915b9e6247bb5bec63e2f79c9afa11fb 100644 (file)
@@ -17,122 +17,280 @@ using System.Runtime.InteropServices;
 namespace System.Data
 {
 
-       [Serializable]\r
+       [Serializable]
        public class ForeignKeyConstraint : Constraint {
 
+               private UniqueConstraint _parentUniqueConstraint;
+               private DataColumn [] _parentColumns;
+               private DataColumn [] _childColumns;
+               private Rule _deleteRule;
+               private Rule _updateRule;
+               private AcceptRejectRule _acceptRejectRule;
+               
                #region Constructors
 
-               [MonoTODO]\r
-               public ForeignKeyConstraint(DataColumn parentColumn, \r
-                       DataColumn childColumn) {
-               }
+               public ForeignKeyConstraint(DataColumn parentColumn, DataColumn childColumn) 
+               {
+                       if (null == parentColumn || null == childColumn) {
+                               throw new ArgumentNullException("Neither parentColumn or" +
+                                       " childColumn can be null.");
+                       }
 
-               [MonoTODO]\r
-               public ForeignKeyConstraint(DataColumn[] parentColumns,\r
-                       DataColumn[] childColumns) {
+                       _foreignKeyConstraint(null, new DataColumn[] {parentColumn},
+                                       new DataColumn[] {childColumn});
                }
 
-               [MonoTODO]\r
-               public ForeignKeyConstraint(string constraintName,\r
-                       DataColumn parentColumn, DataColumn childColumn) {
+               public ForeignKeyConstraint(DataColumn[] parentColumns, DataColumn[] childColumns) 
+               {
+                       _foreignKeyConstraint(null, parentColumns, childColumns);
                }
 
-               [MonoTODO]\r
-               public ForeignKeyConstraint(string constraintName,\r
-                       DataColumn[] parentColumns, \r
-                       DataColumn[] childColumns) {
+               public ForeignKeyConstraint(string constraintName,
+                       DataColumn parentColumn, DataColumn childColumn) 
+               {
+                       if (null == parentColumn || null == childColumn) {
+                               throw new ArgumentNullException("Neither parentColumn or" +
+                                       " childColumn can be null.");
+                       }
+
+                       _foreignKeyConstraint(constraintName, new DataColumn[] {parentColumn},
+                                       new DataColumn[] {childColumn});
                }
 
-               [MonoTODO]\r
-               public ForeignKeyConstraint(string constraintName,\r
-                       string parentTableName, string[] parentColumnNames,\r
-                       string[] childColumnNames, \r
-                       AcceptRejectRule acceptRejectRule, Rule deleteRule,\r
+               public ForeignKeyConstraint(string constraintName,
+                       DataColumn[] parentColumns, DataColumn[] childColumns) 
+               {
+                       _foreignKeyConstraint(constraintName, parentColumns, childColumns);
+               }
+               
+               //special case
+               [MonoTODO]
+               public ForeignKeyConstraint(string constraintName,
+                       string parentTableName, string[] parentColumnNames,
+                       string[] childColumnNames, 
+                       AcceptRejectRule acceptRejectRule, Rule deleteRule,
                        Rule updateRule) {
                }
 
+
+               private void _foreignKeyConstraint(string constraintName, DataColumn[] parentColumns,
+                               DataColumn[] childColumns)
+               {
+
+                       //Validate 
+                       _validateCtor(parentColumns, childColumns);
+
+                       //Set Constraint Name
+                       base.ConstraintName = constraintName;   
+
+                       //Keep reference to columns
+                       _parentColumns = parentColumns;
+                       _childColumns = childColumns;
+               }
+
+               [MonoTODO]
+               private void _validateCtor(DataColumn[] parentColumns, DataColumn[] childColumns)
+               {
+                       //not null
+                       if (null == parentColumns || null == childColumns) 
+                               throw new ArgumentNullException();
+                       
+                       if (parentColumns.Length < 1 || childColumns.Length < 1)
+                               throw new ArgumentException("Neither ParentColumns or ChildColumns can't be" +
+                                               " zero length.");
+                               
+                       //DataTypes must match
+                       //column sets must all be from the same table
+
+                       DataTable ptable = parentColumns[0].Table;
+                       DataTable ctable = childColumns[0].Table;
+               
+                       //not null check
+                       //TODO: columns must belong to a table else ArgumentException
+                       
+                       
+                       foreach (DataColumn pc in parentColumns)
+                       {
+                               
+                               foreach (DataColumn cc in childColumns)
+                               {
+
+                               }       
+                       }
+
+                       //Tables must be from same datasets
+                       if (ptable.DataSet != ctable.DataSet)
+                       {
+                               throw new InvalidOperationException("Tables must belong to the same dataset.");
+                       }
+                       
+               }
+               
                #endregion // Constructors
 
+               #region Helpers
+               private void _validateRemoveParentConstraint(ConstraintCollection sender, 
+                               Constraint constraint, ref bool cancel, ref string failReason)
+               {
+                       //if we hold a reference to the parent then cancel it
+                       if (constraint == _parentUniqueConstraint) 
+                       {
+                               cancel = true;
+                               failReason = "Cannot remove UniqueConstraint because the"
+                                       + " ForeignKeyConstraint " + this.ConstraintName + " exists.";
+                       }
+               }
+               
+               //Checks to see if a related unique constraint exists
+               //if it doesn't then a unique constraint is created.
+               //if a unique constraint can't be created an exception will be thrown
+               private void _ensureUniqueConstraintExists(ConstraintCollection collection,
+                               DataColumn [] parentColumns)
+               {
+                       //not null
+                       if (null == parentColumns) throw new ArgumentNullException(
+                                       "ParentColumns can't be null");
+
+                       UniqueConstraint uc = null;
+
+                       //see if unique constraint already exists
+                       //if not create unique constraint
+                       uc = UniqueConstraint.GetUniqueConstraintForColumnSet(collection, parentColumns);
+
+                       if (null == uc) uc = new UniqueConstraint(parentColumns, false); //could throw
+                       
+                       //keep reference
+                       _parentUniqueConstraint = uc;
+
+                       //if this unique constraint is attempted to be removed before us
+                       //we can fail the validation
+                       collection.ValidateRemoveConstraint += new DelegateValidateRemoveConstraint(
+                                       _validateRemoveParentConstraint);
+               }
+               
+               
+               #endregion //Helpers
+               
+
                #region Properites
-\r
+
                public virtual AcceptRejectRule AcceptRejectRule {
-                       [MonoTODO]
                        get {
-                               throw new NotImplementedException ();
+                               return _acceptRejectRule;
                        }
                        
-                       [MonoTODO]
                        set {
-                               throw new NotImplementedException ();
+                               _acceptRejectRule = value;
                        }
                }
-\r
-               public virtual DataColumn[] Columns {
-                       [MonoTODO]
+
+               public virtual Rule DeleteRule {
                        get {
-                               throw new NotImplementedException ();
+                               return _deleteRule;
+                       }
+                       
+                       set {
+                               _deleteRule = value;
                        }
                }
-\r
-               public virtual Rule DeleteRule {
-                       [MonoTODO]
+
+               public virtual Rule UpdateRule {
                        get {
-                               throw new NotImplementedException ();
+                               return _updateRule;
                        }
                        
-                       [MonoTODO]
                        set {
-                               throw new NotImplementedException ();
+                               _updateRule = value;
+                       }
+               }
+               
+               public virtual DataColumn[] Columns {
+                       get {
+                               return _childColumns;
                        }
                }
-\r
+
                public virtual DataColumn[] RelatedColumns {
-                       [MonoTODO]
                        get {   
-                               throw new NotImplementedException ();
+                               return _parentColumns;
                        }
-               }\r
-\r
+               }
+
                public virtual DataTable RelatedTable {
-                       [MonoTODO]
                        get {
-                               throw new NotImplementedException ();
+                               if (_parentColumns != null)
+                                       if (_parentColumns.Length > 0)
+                                               return _parentColumns[0].Table;
+
+                               return null;
                        }
                }
-\r
+
                public override DataTable Table {
-                       [MonoTODO]
-                       get {
-                               throw new NotImplementedException ();
-                       }
-               }
-\r
-               public virtual Rule UpdateRule {
-                       [MonoTODO]
                        get {
-                               throw new NotImplementedException ();
-                       }
-                       
-                       [MonoTODO]
-                       set {
-                               throw new NotImplementedException ();
+                               if (_childColumns != null)
+                                       if (_childColumns.Length > 0)
+                                               return _childColumns[0].Table;
+
+                               return null;
                        }
                }
 
+       
+
                #endregion // Properties
 
                #region Methods
 
-               [MonoTODO]\r
-               public override bool Equals(object key) {
-                       throw new NotImplementedException ();
+               public override bool Equals(object key) 
+               {
+                       ForeignKeyConstraint fkc = key as ForeignKeyConstraint;
+                       if (null == fkc) return false;
+
+                       //if the fk constrains the same columns then they are equal
+                       if (! DataColumn.AreColumnSetsTheSame( this.RelatedColumns, fkc.RelatedColumns))
+                               return false;
+                       if (! DataColumn.AreColumnSetsTheSame( this.Columns, fkc.Columns) )
+                               return false;
+
+                       return true;
                }
 
-               [MonoTODO]\r
+               [MonoTODO]
                public override int GetHashCode() {
                        throw new NotImplementedException ();
                }
 
+               protected internal override void AddToConstraintCollectionSetup(
+                               ConstraintCollection collection)
+               {
+
+                       //TODO:Should run Ctor rules again
+                       
+                       _ensureUniqueConstraintExists(collection, _parentColumns);
+                       
+               }
+                                       
+       
+               [MonoTODO]
+               protected internal override void RemoveFromConstraintCollectionCleanup( 
+                               ConstraintCollection collection)
+               {
+                       return; //no rules yet          
+               }
+               
+               [MonoTODO]
+               internal override void AssertConstraint()
+               {
+                       //Constraint only works if both tables are part of the same dataset
+                       
+                       //if DataSet ...
+                       
+                       //check for orphaned children
+                       //check for...
+                       
+               }
+               
                #endregion // Methods
        }
 
index fd8b637f20c314edfb8d6098215d2fdb7e7bf2a4..57a14eb68c668419ef07fe7dee4bfc5622e78610 100644 (file)
@@ -15,89 +15,219 @@ using System.Runtime.InteropServices;
 
 namespace System.Data
 {
-       public class UniqueConstraint : Constraint {
+       public class UniqueConstraint : Constraint 
+       {
+               private bool _isPrimaryKey = false;
+               private DataTable _dataTable; //set by ctor except when unique case
+               
+               private DataColumn [] _dataColumns;
+
+               //TODO:provide helpers for this case
+               private string [] _dataColumnNames; //unique case
+               
 
                #region Constructors
 
-               [MonoTODO]\r
                public UniqueConstraint(DataColumn column) {
-                       throw new NotImplementedException ();
+
+                       _uniqueConstraint ("", column, false);
                }
 
-               [MonoTODO]
                public UniqueConstraint(DataColumn[] columns) {
-
-                       throw new NotImplementedException ();
+                       
+                       _uniqueConstraint ("", columns, false);
                }
 
-               [MonoTODO]
-               public UniqueConstraint(DataColumn column,\r
+               public UniqueConstraint(DataColumn column,
                        bool isPrimaryKey) {
 
-                       throw new NotImplementedException ();
+                       _uniqueConstraint ("", column, isPrimaryKey);
                }
 
-               [MonoTODO]
                public UniqueConstraint(DataColumn[] columns, bool isPrimaryKey) {
 
-                       throw new NotImplementedException ();
+                       _uniqueConstraint ("", columns, isPrimaryKey);
                }
 
-               [MonoTODO]
                public UniqueConstraint(string name, DataColumn column) {
 
-                       throw new NotImplementedException ();
+                       _uniqueConstraint (name, column, false);
                }
 
-               [MonoTODO]
                public UniqueConstraint(string name, DataColumn[] columns) {
 
-                       throw new NotImplementedException ();
+                       _uniqueConstraint (name, columns, false);
                }
 
-               [MonoTODO]
-               public UniqueConstraint(string name, DataColumn column,\r
+               public UniqueConstraint(string name, DataColumn column,
                        bool isPrimaryKey) {
 
-                       throw new NotImplementedException ();
+                       _uniqueConstraint (name, column, isPrimaryKey);
                }
 
-               [MonoTODO]
-               public UniqueConstraint(string name,\r
+               public UniqueConstraint(string name,
                        DataColumn[] columns, bool isPrimaryKey) {
 
-                       throw new NotImplementedException ();
+                       _uniqueConstraint (name, columns, isPrimaryKey);
                }
 
+               //Special case.  Can only be added to the Collection with AddRange
                [MonoTODO]
-               public UniqueConstraint(string name,\r
+               public UniqueConstraint(string name,
                        string[] columnNames, bool isPrimaryKey) {
 
-                       throw new NotImplementedException ();
+                       throw new NotImplementedException(); //need to finish related logic
+
+                       base.ConstraintName = name;
+                       
+                       //set unique
+                       //must set unique when added to the collection
+
+                       //keep list of names to resolve later
+                       _dataColumnNames = columnNames;
+
+                       _isPrimaryKey = isPrimaryKey;
                }
 
+               //helper ctor
+               private void _uniqueConstraint(string name, 
+                               DataColumn column, bool isPrimaryKey) {
+
+                       //validate
+                       _validateColumn (column);
+
+                       //Set Constraint Name
+                       base.ConstraintName = name;
+
+                       //set unique
+                       column.Unique = true;
+
+                       //keep reference 
+                       _dataColumns = new DataColumn [] {column};
+                       
+                       //PK?
+                       _isPrimaryKey = isPrimaryKey;
+
+                       //Get table reference
+                       _dataTable = column.Table;
+               }
+
+               //helpter ctor  
+               public void _uniqueConstraint(string name,
+                       DataColumn[] columns, bool isPrimaryKey) {
+
+                       //validate
+                       _validateColumns (columns, out _dataTable);
+
+                       //Set Constraint Name
+                       base.ConstraintName = name;
+
+                       //set unique
+                       _setColumnsUnique (columns);
+
+                       //keep reference
+                       _dataColumns = columns;
+
+                       //PK?
+                       _isPrimaryKey = isPrimaryKey;
+
+               }
+               
                #endregion // Constructors
+
+               #region Helpers
+               private void _setColumnsUnique(DataColumn [] columns) {
+                       if (null == columns) return;
+                       foreach (DataColumn col in columns) {
+                               col.Unique = true;
+                       }
+               }
+               
+               //Validates a collection of columns with the ctor rules
+               private void _validateColumns(DataColumn [] columns, out DataTable table) {
+                       table = null;
+
+                       //not null
+                       if (null == columns) throw new ArgumentNullException();
+                       
+                       //check that there is at least one column
+                       //LAMESPEC: not in spec
+                       if (columns.Length < 1)
+                               throw new InvalidConstraintException("Must be at least one column.");
+                       
+                       DataTable compareTable = columns[0].Table;
+                       //foreach
+                       foreach (DataColumn col in columns){
+                       
+                               //check individual column rules
+                               _validateColumn (col);
+                               
+                               
+                               //check that columns are all from the same table??
+                               //LAMESPEC: not in spec
+                               if (compareTable != col.Table)
+                                       throw new InvalidConstraintException("Columns must be from the same table.");
+                               
+                       }
+
+                       table = compareTable;
+               }
+               
+               //validates a column with the ctor rules
+               private void _validateColumn(DataColumn column) {
+       
+                       //not null
+                       if (null == column) throw new ArgumentNullException();
+                       
+                       //column must belong to a table
+                       //LAMESPEC: not in spec
+                       if (null == column.Table) 
+                               throw new ArgumentException("Column " + column.ColumnName + " must belong to a table.");
+                       
+               }
+
+               internal static UniqueConstraint GetUniqueConstraintForColumnSet(ConstraintCollection collection,
+                               DataColumn[] columns)
+               {
+                       if (null == columns ) return null;
+                       
+                       UniqueConstraint uniqueConstraint;
+                       IEnumerator enumer = collection.GetEnumerator();
+                       while (enumer.MoveNext())
+                       {
+                               uniqueConstraint = enumer.Current as UniqueConstraint;
+                               if (uniqueConstraint != null)
+                               {
+                                       if ( DataColumn.AreColumnSetsTheSame(uniqueConstraint.Columns, columns) )
+                                       {
+                                               return uniqueConstraint;
+                                       }
+                               }
+                       }
+                       return null;
+               }
+                       
                
+                       
+               #endregion //Helpers
+
                #region Properties
 
                public virtual DataColumn[] Columns {
-                       [MonoTODO]
                        get {
-                               throw new NotImplementedException ();
+                               return _dataColumns;
                        }
                }
 
                public bool IsPrimaryKey {
-                       [MonoTODO]
                        get {
-                               throw new NotImplementedException ();
+                               return _isPrimaryKey;
                        }
                }
 
                public override DataTable Table {
-                       [MonoTODO]
                        get {
-                               throw new NotImplementedException ();
+                               return _dataTable;
                        }
                }
 
@@ -106,31 +236,45 @@ namespace System.Data
                #region Methods
 
                public override bool Equals(object key2) {
+
                        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;
-                       }
+                       return DataColumn.AreColumnSetsTheSame(cst.Columns, this.Columns);      
 
-                       //if we got here then all columns were found
-                       return true;
-                       
                }
 
                [MonoTODO]
                public override int GetHashCode() {
                        throw new NotImplementedException ();
                }
+               
+       
+               internal protected override void AddToConstraintCollectionSetup(
+                               ConstraintCollection collection)
+               {
+                       //TODO:Should run Ctor rules again
+                       
+                       //make sure a unique constraint doesn't already exists for these columns
+                       UniqueConstraint uc = UniqueConstraint.GetUniqueConstraintForColumnSet(collection, this.Columns);       
+                       if (null != uc) throw new ArgumentException("Unique constraint already exists for these" +
+                                       " columns.");
+                                       
+               }
+                                       
+               
+               internal protected override void RemoveFromConstraintCollectionCleanup( 
+                               ConstraintCollection collection)
+               {
+               }
 
+               [MonoTODO]
+               internal override void AssertConstraint()
+               {
+                       //Unique?
+               }
                #endregion // Methods
        }
 }
index aa161ebd34d855bbcd245266d01f6f92bf4d6bc7..46bb4d2fd6b519a10f57380313f214f6f29bf526 100644 (file)
@@ -1,3 +1,13 @@
+2002-08-15  Franklin Wise <gracenote@earthlink.net>
+       
+       * AllTests.cs: Added ForeignKeyConstraintTest to active running tests.
+               
+       * NewFile: System.Data\ForeignKeyConstraintTest.cs
+       
+       * System.Data\ConstraintTest: Added new test.
+
+       * System.Data\UniqueConstraintTest:  Added more tests.
+       
 2002-08-14  Daniel Morgan <danmorg@sc.rr.com>
 
        * SqlSharpCli.cs: modified
index 1752c3bfc7b3d9e85a9acd3e2d94f725935a1b37..77f3bbc8e2afd22d14749d429ef8f1864f40f7f4 100644 (file)
@@ -25,6 +25,7 @@ namespace MonoTests.System.Data
                                suite.AddTest (new TestSuite (typeof (UniqueConstraintTest)));
                                suite.AddTest (new TestSuite (typeof (ConstraintTest)));
                                suite.AddTest (new TestSuite (typeof (ConstraintCollectionTest)));
+                               suite.AddTest (new TestSuite (typeof (ForeignKeyConstraintTest)));
                                return suite;
                        }
                }
index c1d2ddcd1e4ef7bc73458115b7ca6ddc82a24ad6..71efd493698ba5b9101487ebc5c2dc4b8d528d96 100644 (file)
@@ -20,6 +20,7 @@ namespace MonoTests.System.Data
        public class ConstraintCollectionTest : TestCase 
        {
                private DataTable _table;
+               private DataTable _table2;
                private Constraint _constraint1;
                private Constraint _constraint2;
 
@@ -33,6 +34,11 @@ namespace MonoTests.System.Data
                        _table = new DataTable("TestTable");
                        _table.Columns.Add("Col1",typeof(int));
                        _table.Columns.Add("Col2",typeof(int));
+                       _table.Columns.Add("Col3",typeof(int));
+
+                       _table2 = new DataTable("TestTable");
+                       _table2.Columns.Add("Col1",typeof(int));
+                       _table2.Columns.Add("Col2",typeof(int));
 
                        //Use UniqueConstraint to test Constraint Base Class
                        _constraint1 = new UniqueConstraint(_table.Columns[0],false); 
@@ -61,6 +67,8 @@ namespace MonoTests.System.Data
                public void TestAddExceptions()
                {
                        ConstraintCollection col = _table.Constraints;
+                       
+                       //null
                        try 
                        {
                                col.Add(null);
@@ -73,6 +81,7 @@ namespace MonoTests.System.Data
                                Assertion.Fail("A1: Wrong exception type");
                        }
 
+                       //duplicate name
                        try 
                        {
                                _constraint1.ConstraintName = "Dog";
@@ -102,6 +111,209 @@ namespace MonoTests.System.Data
                        }
                }
 
+               public void TestIndexer()
+               {
+                       Constraint c1 = new UniqueConstraint(_table.Columns[0]);
+                       Constraint c2 = new UniqueConstraint(_table.Columns[1]);
+
+                       c1.ConstraintName = "first";
+                       c2.ConstraintName = "second";
+
+
+                       _table.Constraints.Add(c1);
+                       _table.Constraints.Add(c2);
+
+                       Assertion.AssertSame("A1", c1, _table.Constraints[0]); 
+                       Assertion.AssertSame("A2", c2, _table.Constraints[1]);
+
+                       Assertion.AssertSame("A3", c1, _table.Constraints["first"]);
+                       Assertion.AssertSame("A4", c2, _table.Constraints["sEcond"]); //case insensitive
+
+               }
+
+               public void TestIndexOf()
+               {
+                       Constraint c1 = new UniqueConstraint(_table.Columns[0]);
+                       Constraint c2 = new UniqueConstraint(_table.Columns[1]);
+
+                       c1.ConstraintName = "first";
+                       c2.ConstraintName = "second";
+
+                       _table.Constraints.Add(c1);
+                       _table.Constraints.Add(c2);
+
+                       Assertion.AssertEquals("A1", 0, _table.Constraints.IndexOf(c1));
+                       Assertion.AssertEquals("A2", 1, _table.Constraints.IndexOf(c2));
+                       Assertion.AssertEquals("A3", 0, _table.Constraints.IndexOf("first"));
+                       Assertion.AssertEquals("A4", 1, _table.Constraints.IndexOf("second"));
+               }
+
+               public void TestContains()
+               {
+                       Constraint c1 = new UniqueConstraint(_table.Columns[0]);
+                       Constraint c2 = new UniqueConstraint(_table.Columns[1]);
+
+                       c1.ConstraintName = "first";
+                       c2.ConstraintName = "second";
+
+                       _table.Constraints.Add(c1);
+
+                       Assertion.Assert("A1", _table.Constraints.Contains(c1.ConstraintName)); //true
+                       Assertion.Assert("A2", _table.Constraints.Contains(c2.ConstraintName) == false); //doesn't contain
+               }
+
+               public void TestIndexerFailures()
+               {
+                       _table.Constraints.Add(new UniqueConstraint(_table.Columns[0]));
+
+                       //This doesn't throw
+                       Assertion.AssertNull(_table.Constraints["notInCollection"]);
+                       
+                       //Index too high
+                       try 
+                       {
+                               Constraint c = _table.Constraints[_table.Constraints.Count];
+                               Assertion.Fail("B1: Failed to throw IndexOutOfRangeException.");
+                       }
+                       catch (IndexOutOfRangeException) {}
+                       catch (AssertionFailedError exc) {throw exc;}
+                       catch 
+                       {
+                               Assertion.Fail("A1: Wrong exception type");
+                       }
+
+                       //Index too low
+                       try 
+                       {
+                               Constraint c = _table.Constraints[-1];
+                               Assertion.Fail("B2: Failed to throw IndexOutOfRangeException.");
+                       }
+                       catch (IndexOutOfRangeException) {}
+                       catch (AssertionFailedError exc) {throw exc;}
+                       catch 
+                       {
+                               Assertion.Fail("A2: Wrong exception type");
+                       }       
+
+               }
+
+               //TODO: Implementation not ready for this test yet
+//             public void TestAddFkException1()
+//             {
+//                     DataSet ds = new DataSet();
+//                     ds.Tables.Add(_table);
+//                     ds.Tables.Add(_table2);
+//
+//                     _table.Rows.Add(new object [] {1});
+//                     _table.Rows.Add(new object [] {1});
+//
+//                     //FKC: can't create unique constraint because duplicate values already exist
+//                     try
+//                     {
+//                             ForeignKeyConstraint fkc = new ForeignKeyConstraint( _table.Columns[0],
+//                                                                                     _table2.Columns[0]);
+//                             
+//                             _table2.Constraints.Add(fkc);   //should throw                  
+//                             Assertion.Fail("B1: Failed to throw ArgumentException.");
+//                     }
+//                     catch (ArgumentException) {}
+//                     catch (AssertionFailedError exc) {throw exc;}
+//                     catch (Exception exc)
+//                     {
+//                             Assertion.Fail("A1: Wrong Exception type. " + exc.ToString());
+//                     }
+//
+//
+//             }
+
+
+               //TODO: Implementation not ready for this test yet
+//             public void TestAddFkException2()
+//             {
+//                     //Foreign key rules only work when the tables
+//                     //are apart of the dataset
+//                     DataSet ds = new DataSet();
+//                     ds.Tables.Add(_table);
+//                     ds.Tables.Add(_table2);
+//
+//                     _table.Rows.Add(new object [] {1});
+//                     
+//                     // will need a matching parent value in 
+//                     // _table
+//                     _table2.Rows.Add(new object [] {3}); 
+//                                                             
+//
+//                     //FKC: no matching parent value
+//                     try
+//                     {
+//                             ForeignKeyConstraint fkc = new ForeignKeyConstraint( _table.Columns[0],
+//                                     _table2.Columns[0]);
+//                             
+//                             _table2.Constraints.Add(fkc);   //should throw                  
+//                             Assertion.Fail("B1: Failed to throw ArgumentException.");
+//                     }
+//                     catch (ArgumentException) {}
+//                     catch (AssertionFailedError exc) {throw exc;}
+//                     catch (Exception exc)
+//                     {
+//                             Assertion.Fail("A1: Wrong Exception type. " + exc.ToString());
+//                     }
+//
+//
+//             }
+
+
+               //TODO: Implementation not ready for this test yet
+//             public void TestAddUniqueExceptions()
+//             {
+//                     
+//
+//                     //UC: can't create unique constraint because duplicate values already exist
+//                     try
+//                     {
+//                             _table.Rows.Add(new object [] {1});
+//                             _table.Rows.Add(new object [] {1});
+//                             UniqueConstraint uc = new UniqueConstraint( _table.Columns[0]);
+//                             
+//                             _table.Constraints.Add(uc);     //should throw                  
+//                             Assertion.Fail("B1: Failed to throw ArgumentException.");
+//                     }
+//                     catch (ArgumentException) {}
+//                     catch (AssertionFailedError exc) {throw exc;}
+//                     catch (Exception exc)
+//                     {
+//                             Assertion.Fail("A1: Wrong Exception type. " + exc.ToString());
+//                     }
+//             }
+
+               public void TestAddRange()
+               {
+               }
+
+               public void TestClear()
+               {
+
+               }
+
+               public void TestCanRemove()
+               {
+
+               }
+
+               public void TestCollectionChanged()
+               {
+
+               }
+
+               public void TestRemoveAt()
+               {
+               }
+
+               public void TestRemove()
+               {
+               }
+
+
                public void TestRemoveExceptions()
                {
 
index a019e9c6b7d9f71503c471f7ad4f8b302b2a79c2..e88883a4314fd281d62348d459e7b86eb8829dc0 100644 (file)
@@ -116,8 +116,11 @@ namespace MonoTests.System.Data
                }
 
                public void TestToString() {
-                       //_constraint1.ConstraintName = "Test";
+                       _constraint1.ConstraintName = "Test";
                        Assertion.Assert("ToString is the same as constraint name.", _constraint1.ConstraintName.CompareTo( _constraint1.ToString()) == 0);
+                       
+                       _constraint1.ConstraintName = null;
+                       Assertion.AssertNotNull("ToString should return empty.",_constraint1.ToString());
                }
 
                public void TestGetExtendedProperties() {
diff --git a/mcs/class/System.Data/Test/System.Data/ForeignKeyConstraintTest.cs b/mcs/class/System.Data/Test/System.Data/ForeignKeyConstraintTest.cs
new file mode 100644 (file)
index 0000000..84d11c3
--- /dev/null
@@ -0,0 +1,124 @@
+// ForeignKeyConstraintTest.cs - NUnit Test Cases for [explain here]
+//
+// Franklin Wise (gracenote@earthlink.net)
+//
+// (C) Franklin Wise
+// 
+
+
+using NUnit.Framework;
+using System;
+using System.Data;
+
+namespace MonoTests.System.Data
+{
+
+       public class ForeignKeyConstraintTest : TestCase 
+       {
+               private DataSet _ds;
+
+               //NOTE: fk constraints only work when the table is part of a DataSet
+
+               public ForeignKeyConstraintTest() : base ("MonoTests.System.Data.ForeignKeyConstraintTest") {}
+               public ForeignKeyConstraintTest(string name) : base(name) {}
+
+               protected override void SetUp() 
+               {
+                       _ds = new DataSet();
+
+                       //Setup DataTable
+                       DataTable table;
+                       table = new DataTable("TestTable");
+                       table.Columns.Add("Col1",typeof(int));
+                       table.Columns.Add("Col2",typeof(int));
+                       table.Columns.Add("Col3",typeof(int));
+
+                       _ds.Tables.Add(table);
+
+                       table = new DataTable("TestTable2");
+                       table.Columns.Add("Col1",typeof(int));
+                       table.Columns.Add("Col2",typeof(int));
+                       table.Columns.Add("Col3",typeof(int));
+
+                       _ds.Tables.Add(table);
+
+               }
+
+               protected override void TearDown() {}
+
+               public static ITest Suite 
+               {
+                       get 
+                       { 
+                               return new TestSuite(typeof(ForeignKeyConstraintTest)); 
+                       }
+               }
+
+
+               public void TestCtorExceptions ()
+               {
+                       ForeignKeyConstraint fkc;
+
+                       DataTable localTable = new DataTable();
+                       localTable.Columns.Add("Col1",typeof(int));
+                       localTable.Columns.Add("Col2",typeof(bool));
+
+                       //Null
+                       try
+                       {
+                               fkc = new ForeignKeyConstraint((DataColumn)null,(DataColumn)null);
+                               Assertion.Fail("Failed to throw ArgumentNullException.");
+                       }
+                       catch (ArgumentNullException) {}
+                       catch (AssertionFailedError exc) {throw exc;}
+                       catch (Exception exc)
+                       {
+                               Assertion.Fail("A1: Wrong Exception type. " + exc.ToString());
+                       }
+
+                       //zero length collection
+                       try
+                       {
+                               fkc = new ForeignKeyConstraint(new DataColumn[]{},new DataColumn[]{});
+                               Assertion.Fail("B1: Failed to throw ArgumentException.");
+                       }
+                       catch (ArgumentException) {}
+                       catch (AssertionFailedError exc) {throw exc;}
+                       catch (Exception exc)
+                       {
+                               Assertion.Fail("A1: Wrong Exception type. " + exc.ToString());
+                       }
+
+                       //different datasets
+                       try
+                       {
+                               fkc = new ForeignKeyConstraint(_ds.Tables[0].Columns[0], localTable.Columns[0]);
+                               Assertion.Fail("Failed to throw InvalidOperationException.");
+                       }
+                       catch (InvalidOperationException) {}
+                       catch (AssertionFailedError exc) {throw exc;}
+                       catch (Exception exc)
+                       {
+                               Assertion.Fail("A1: Wrong Exception type. " + exc.ToString());
+                       }
+
+                       //different dataTypes
+                       try
+                       {
+                               fkc = new ForeignKeyConstraint(_ds.Tables[0].Columns[0], localTable.Columns[1]);
+                               Assertion.Fail("Failed to throw InvalidOperationException.");
+                       }
+                       catch (InvalidOperationException) {}
+                       catch (AssertionFailedError exc) {throw exc;}
+                       catch (Exception exc)
+                       {
+                               Assertion.Fail("A1: Wrong Exception type. " + exc.ToString());
+                       }
+
+                       
+
+
+
+               }
+       }
+}
index 2eaf18de9aaf39867ba02c1262ea1240e7654dde..590720d4c7d731f86d0f530fc31cca77c666bc0e 100644 (file)
@@ -25,6 +25,7 @@ namespace MonoTests.System.Data
                        _table = new DataTable("TestTable");
                        _table.Columns.Add("Col1",typeof(int));
                        _table.Columns.Add("Col2",typeof(int));
+                       _table.Columns.Add("Col3",typeof(int));
 
                }  
 
@@ -143,6 +144,13 @@ namespace MonoTests.System.Data
                                      _table.Columns[0], _table.Columns[1]});
                        Assertion.AssertSame ("B2", cst.Table, _table);
 
+                       cst = new UniqueConstraint("MyName",_table.Columns[0],true);
+
+                       //Test ctor parm set for ConstraintName & IsPrimaryKey
+                       Assertion.AssertEquals("ConstraintName not set in ctor.", 
+                               "MyName", cst.ConstraintName);
+                       Assertion.AssertEquals("IsPrimaryKey not set in ctor.",
+                               true, cst.IsPrimaryKey);
                
                }
 
@@ -150,17 +158,19 @@ namespace MonoTests.System.Data
                        UniqueConstraint cst = new UniqueConstraint( new DataColumn [] {
                                        _table.Columns[0], _table.Columns[1]});
                        UniqueConstraint cst2 = new UniqueConstraint( new DataColumn [] {
-                                       _table.Columns[0], _table.Columns[1]});
+                                        _table.Columns[1], _table.Columns[0]});
 
                        UniqueConstraint cst3 = new UniqueConstraint(_table.Columns[0]);
+                       UniqueConstraint cst4 = new UniqueConstraint(_table.Columns[2]);
                        
                        //true
                        Assertion.Assert(cst.Equals(cst2) == true);
                        
                        //false
-                       Assertion.Assert(cst.Equals(23) == false);
-                       Assertion.Assert(cst.Equals(cst3) == false);
-
+                       Assertion.Assert("A1", cst.Equals(23) == false);
+                       Assertion.Assert("A2", cst.Equals(cst3) == false);
+                       Assertion.Assert("A3", cst3.Equals(cst) == false);
+                       Assertion.Assert("A4", cst.Equals(cst4) == false);
 
                }