1 // Licensed to the .NET Foundation under one or more agreements. 2 // See the LICENSE file in the project root for more information. 3 4 // (C) Franklin Wise 5 // (C) 2003 Martin Willemoes Hansen 6 7 // Copyright (C) 2004 Novell, Inc (http://www.novell.com) 8 // 9 // Permission is hereby granted, free of charge, to any person obtaining 10 // a copy of this software and associated documentation files (the 11 // "Software"), to deal in the Software without restriction, including 12 // without limitation the rights to use, copy, modify, merge, publish, 13 // distribute, sublicense, and/or sell copies of the Software, and to 14 // permit persons to whom the Software is furnished to do so, subject to 15 // the following conditions: 16 // 17 // The above copyright notice and this permission notice shall be 18 // included in all copies or substantial portions of the Software. 19 // 20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 28 using Xunit; 29 30 namespace System.Data.Tests 31 { 32 public class ForeignKeyConstraintTest 33 { 34 private DataSet _ds; 35 36 //NOTE: fk constraints only work when the table is part of a DataSet 37 ForeignKeyConstraintTest()38 public ForeignKeyConstraintTest() 39 { 40 _ds = new DataSet(); 41 42 //Setup DataTable 43 DataTable table; 44 table = new DataTable("TestTable"); 45 table.Columns.Add("Col1", typeof(int)); 46 table.Columns.Add("Col2", typeof(int)); 47 table.Columns.Add("Col3", typeof(int)); 48 49 _ds.Tables.Add(table); 50 51 table = new DataTable("TestTable2"); 52 table.Columns.Add("Col1", typeof(int)); 53 table.Columns.Add("Col2", typeof(int)); 54 table.Columns.Add("Col3", typeof(int)); 55 56 _ds.Tables.Add(table); 57 } 58 59 // Tests ctor (string, DataColumn, DataColumn) 60 [Fact] Ctor1()61 public void Ctor1() 62 { 63 DataTable Table = _ds.Tables[0]; 64 65 Assert.Equal(0, Table.Constraints.Count); 66 Table = _ds.Tables[1]; 67 Assert.Equal(0, Table.Constraints.Count); 68 69 // ctor (string, DataColumn, DataColumn 70 ForeignKeyConstraint Constraint = new ForeignKeyConstraint("test", _ds.Tables[0].Columns[2], _ds.Tables[1].Columns[0]); 71 Table = _ds.Tables[1]; 72 Table.Constraints.Add(Constraint); 73 74 Assert.Equal(1, Table.Constraints.Count); 75 Assert.Equal("test", Table.Constraints[0].ConstraintName); 76 Assert.Equal(typeof(ForeignKeyConstraint), Table.Constraints[0].GetType()); 77 78 Table = _ds.Tables[0]; 79 Assert.Equal(1, Table.Constraints.Count); 80 Assert.Equal("Constraint1", Table.Constraints[0].ConstraintName); 81 Assert.Equal(typeof(UniqueConstraint), Table.Constraints[0].GetType()); 82 } 83 84 // Tests ctor (DataColumn, DataColumn) 85 [Fact] Ctor2()86 public void Ctor2() 87 { 88 DataTable Table = _ds.Tables[0]; 89 90 Assert.Equal(0, Table.Constraints.Count); 91 Table = _ds.Tables[1]; 92 Assert.Equal(0, Table.Constraints.Count); 93 94 // ctor (string, DataColumn, DataColumn 95 ForeignKeyConstraint Constraint = new ForeignKeyConstraint(_ds.Tables[0].Columns[2], _ds.Tables[1].Columns[0]); 96 Table = _ds.Tables[1]; 97 Table.Constraints.Add(Constraint); 98 99 Assert.Equal(1, Table.Constraints.Count); 100 Assert.Equal("Constraint1", Table.Constraints[0].ConstraintName); 101 Assert.Equal(typeof(ForeignKeyConstraint), Table.Constraints[0].GetType()); 102 103 Table = _ds.Tables[0]; 104 Assert.Equal(1, Table.Constraints.Count); 105 Assert.Equal("Constraint1", Table.Constraints[0].ConstraintName); 106 Assert.Equal(typeof(UniqueConstraint), Table.Constraints[0].GetType()); 107 } 108 109 // Test ctor (DataColumn [], DataColumn []) 110 [Fact] Ctor3()111 public void Ctor3() 112 { 113 DataTable Table = _ds.Tables[0]; 114 115 Assert.Equal(0, Table.Constraints.Count); 116 Table = _ds.Tables[1]; 117 Assert.Equal(0, Table.Constraints.Count); 118 119 DataColumn[] Cols1 = new DataColumn[2]; 120 Cols1[0] = _ds.Tables[0].Columns[1]; 121 Cols1[1] = _ds.Tables[0].Columns[2]; 122 123 DataColumn[] Cols2 = new DataColumn[2]; 124 Cols2[0] = _ds.Tables[1].Columns[0]; 125 Cols2[1] = _ds.Tables[1].Columns[1]; 126 127 ForeignKeyConstraint Constraint = new ForeignKeyConstraint(Cols1, Cols2); 128 Table = _ds.Tables[1]; 129 Table.Constraints.Add(Constraint); 130 131 Assert.Equal(1, Table.Constraints.Count); 132 Assert.Equal("Constraint1", Table.Constraints[0].ConstraintName); 133 Assert.Equal(typeof(ForeignKeyConstraint), Table.Constraints[0].GetType()); 134 135 Table = _ds.Tables[0]; 136 Assert.Equal(1, Table.Constraints.Count); 137 Assert.Equal("Constraint1", Table.Constraints[0].ConstraintName); 138 Assert.Equal(typeof(UniqueConstraint), Table.Constraints[0].GetType()); 139 } 140 141 // Tests ctor (string, DataColumn [], DataColumn []) 142 [Fact] Ctor4()143 public void Ctor4() 144 { 145 DataTable Table = _ds.Tables[0]; 146 147 Assert.Equal(0, Table.Constraints.Count); 148 Table = _ds.Tables[1]; 149 Assert.Equal(0, Table.Constraints.Count); 150 151 DataColumn[] Cols1 = new DataColumn[2]; 152 Cols1[0] = _ds.Tables[0].Columns[1]; 153 Cols1[1] = _ds.Tables[0].Columns[2]; 154 155 DataColumn[] Cols2 = new DataColumn[2]; 156 Cols2[0] = _ds.Tables[1].Columns[0]; 157 Cols2[1] = _ds.Tables[1].Columns[1]; 158 159 ForeignKeyConstraint Constraint = new ForeignKeyConstraint("Test", Cols1, Cols2); 160 Table = _ds.Tables[1]; 161 Table.Constraints.Add(Constraint); 162 163 Assert.Equal(1, Table.Constraints.Count); 164 Assert.Equal("Test", Table.Constraints[0].ConstraintName); 165 Assert.Equal(typeof(ForeignKeyConstraint), Table.Constraints[0].GetType()); 166 167 Table = _ds.Tables[0]; 168 Assert.Equal(1, Table.Constraints.Count); 169 Assert.Equal("Constraint1", Table.Constraints[0].ConstraintName); 170 Assert.Equal(typeof(UniqueConstraint), Table.Constraints[0].GetType()); 171 } 172 173 [Fact] TestCtor5()174 public void TestCtor5() 175 { 176 DataTable table1 = new DataTable("Table1"); 177 DataTable table2 = new DataTable("Table2"); 178 DataSet dataSet = new DataSet(); 179 dataSet.Tables.Add(table1); 180 dataSet.Tables.Add(table2); 181 DataColumn column1 = new DataColumn("col1"); 182 DataColumn column2 = new DataColumn("col2"); 183 DataColumn column3 = new DataColumn("col3"); 184 table1.Columns.Add(column1); 185 table1.Columns.Add(column2); 186 table1.Columns.Add(column3); 187 DataColumn column4 = new DataColumn("col4"); 188 DataColumn column5 = new DataColumn("col5"); 189 DataColumn column6 = new DataColumn("col6"); 190 table2.Columns.Add(column4); 191 table2.Columns.Add(column5); 192 table2.Columns.Add(column6); 193 string[] parentColumnNames = { "col1", "col2", "col3" }; 194 string[] childColumnNames = { "col4", "col5", "col6" }; 195 string parentTableName = "table1"; 196 197 // Create a ForeingKeyConstraint Object using the constructor 198 // ForeignKeyConstraint (string, string, string[], string[], AcceptRejectRule, Rule, Rule); 199 ForeignKeyConstraint fkc = new ForeignKeyConstraint("hello world", parentTableName, parentColumnNames, childColumnNames, AcceptRejectRule.Cascade, Rule.Cascade, Rule.Cascade); // Assert that the Constraint object does not belong to any table yet 200 try 201 { 202 DataTable tmp = fkc.Table; 203 Assert.False(true); 204 } 205 catch (NullReferenceException) 206 { // actually .NET throws this (bug) 207 } 208 catch (InvalidOperationException) 209 { 210 } 211 212 Constraint[] constraints = new Constraint[3]; 213 constraints[0] = new UniqueConstraint(column1); 214 constraints[1] = new UniqueConstraint(column2); 215 constraints[2] = fkc; 216 217 // Try to add the constraint to ConstraintCollection of the DataTable through Add() 218 try 219 { 220 table2.Constraints.Add(fkc); 221 throw new ApplicationException("An Exception was expected"); 222 } 223 // LAMESPEC : spec says InvalidConstraintException but throws this 224 catch (NullReferenceException) 225 { 226 } 227 228 #if false // FIXME: Here this test crashes under MS.NET. 229 // OK - So AddRange() is the only way! 230 table2.Constraints.AddRange (constraints); 231 // After AddRange(), Check the properties of ForeignKeyConstraint object 232 Assert.True(fkc.RelatedColumns [0].ColumnName.Equals ("col1")); 233 Assert.True(fkc.RelatedColumns [1].ColumnName.Equals ("col2")); 234 Assert.True(fkc.RelatedColumns [2].ColumnName.Equals ("col3")); 235 Assert.True(fkc.Columns [0].ColumnName.Equals ("col4")); 236 Assert.True(fkc.Columns [1].ColumnName.Equals ("col5")); 237 Assert.True(fkc.Columns [2].ColumnName.Equals ("col6")); 238 #endif 239 // Try to add columns with names which do not exist in the table 240 parentColumnNames[2] = "noColumn"; 241 ForeignKeyConstraint foreignKeyConstraint = new ForeignKeyConstraint("hello world", parentTableName, parentColumnNames, childColumnNames, AcceptRejectRule.Cascade, Rule.Cascade, Rule.Cascade); 242 constraints[0] = new UniqueConstraint(column1); 243 constraints[1] = new UniqueConstraint(column2); 244 constraints[2] = foreignKeyConstraint; 245 try 246 { 247 table2.Constraints.AddRange(constraints); 248 throw new ApplicationException("An Exception was expected"); 249 } 250 catch (ArgumentException e) 251 { 252 } 253 catch (InvalidConstraintException e) 254 { // Could not test on ms.net, as ms.net does not reach here so far. 255 } 256 257 #if false // FIXME: Here this test crashes under MS.NET. 258 // Check whether the child table really contains the foreign key constraint named "hello world" 259 Assert.True(table2.Constraints.Contains ("hello world")); 260 #endif 261 } 262 263 264 265 // If Childs and parents are in same table 266 [Fact] KeyBetweenColumns()267 public void KeyBetweenColumns() 268 { 269 DataTable Table = _ds.Tables[0]; 270 271 Assert.Equal(0, Table.Constraints.Count); 272 Table = _ds.Tables[1]; 273 Assert.Equal(0, Table.Constraints.Count); 274 275 276 ForeignKeyConstraint Constraint = new ForeignKeyConstraint("Test", _ds.Tables[0].Columns[0], _ds.Tables[0].Columns[2]); 277 Table = _ds.Tables[0]; 278 Table.Constraints.Add(Constraint); 279 280 Assert.Equal(2, Table.Constraints.Count); 281 Assert.Equal("Constraint1", Table.Constraints[0].ConstraintName); 282 Assert.Equal(typeof(UniqueConstraint), Table.Constraints[0].GetType()); 283 Assert.Equal("Test", Table.Constraints[1].ConstraintName); 284 Assert.Equal(typeof(ForeignKeyConstraint), Table.Constraints[1].GetType()); 285 } 286 287 [Fact] CtorExceptions()288 public void CtorExceptions() 289 { 290 ForeignKeyConstraint fkc; 291 292 DataTable localTable = new DataTable(); 293 localTable.Columns.Add("Col1", typeof(int)); 294 localTable.Columns.Add("Col2", typeof(bool)); 295 296 //Null 297 Assert.Throws<NullReferenceException>(() => 298 { 299 fkc = new ForeignKeyConstraint(null, (DataColumn)null); 300 }); 301 302 //zero length collection 303 AssertExtensions.Throws<ArgumentException>(null, () => 304 { 305 fkc = new ForeignKeyConstraint(new DataColumn[] { }, new DataColumn[] { }); 306 }); 307 308 //different datasets 309 Assert.Throws<InvalidOperationException>(() => 310 { 311 fkc = new ForeignKeyConstraint(_ds.Tables[0].Columns[0], localTable.Columns[0]); 312 }); 313 314 Assert.Throws<InvalidOperationException>(() => 315 { 316 fkc = new ForeignKeyConstraint(_ds.Tables[0].Columns[0], localTable.Columns[1]); 317 }); 318 319 // Cannot create a Key from Columns that belong to 320 // different tables. 321 Assert.Throws<InvalidConstraintException>(() => 322 { 323 fkc = new ForeignKeyConstraint(new DataColumn[] { _ds.Tables[0].Columns[0], _ds.Tables[0].Columns[1] }, new DataColumn[] { localTable.Columns[1], _ds.Tables[1].Columns[0] }); 324 }); 325 } 326 327 [Fact] CtorExceptions2()328 public void CtorExceptions2() 329 { 330 DataColumn col = new DataColumn("MyCol1", typeof(int)); 331 332 ForeignKeyConstraint fkc; 333 334 //Columns must belong to a Table 335 AssertExtensions.Throws<ArgumentException>(null, () => 336 { 337 fkc = new ForeignKeyConstraint(col, _ds.Tables[0].Columns[0]); 338 }); 339 340 //Columns must belong to the same table 341 //InvalidConstraintException 342 343 DataColumn[] difTable = new DataColumn[] {_ds.Tables[0].Columns[2], 344 _ds.Tables[1].Columns[0]}; 345 Assert.Throws<InvalidConstraintException>(() => 346 { 347 fkc = new ForeignKeyConstraint(difTable, new DataColumn[] { 348 _ds.Tables[0].Columns[1], 349 _ds.Tables[0].Columns[0]}); 350 }); 351 352 //parent columns and child columns should be the same length 353 //ArgumentException 354 DataColumn[] twoCol = 355 new DataColumn[] { _ds.Tables[0].Columns[0], _ds.Tables[0].Columns[1] }; 356 357 358 AssertExtensions.Throws<ArgumentException>(null, () => 359 { 360 fkc = new ForeignKeyConstraint(twoCol, 361 new DataColumn[] { _ds.Tables[0].Columns[0] }); 362 }); 363 364 //InvalidOperation: Parent and child are the same column. 365 Assert.Throws<InvalidOperationException>(() => 366 { 367 fkc = new ForeignKeyConstraint(_ds.Tables[0].Columns[0], 368 _ds.Tables[0].Columns[0]); 369 }); 370 } 371 372 [Fact] EqualsAndHashCode()373 public void EqualsAndHashCode() 374 { 375 DataTable tbl = _ds.Tables[0]; 376 DataTable tbl2 = _ds.Tables[1]; 377 378 ForeignKeyConstraint fkc = new ForeignKeyConstraint( 379 new DataColumn[] { tbl.Columns[0], tbl.Columns[1] }, 380 new DataColumn[] { tbl2.Columns[0], tbl2.Columns[1] }); 381 382 ForeignKeyConstraint fkc2 = new ForeignKeyConstraint( 383 new DataColumn[] { tbl.Columns[0], tbl.Columns[1] }, 384 new DataColumn[] { tbl2.Columns[0], tbl2.Columns[1] }); 385 386 ForeignKeyConstraint fkcDiff = 387 new ForeignKeyConstraint(tbl.Columns[1], tbl.Columns[2]); 388 389 Assert.True(fkc.Equals(fkc2)); 390 Assert.True(fkc2.Equals(fkc)); 391 Assert.True(fkc.Equals(fkc)); 392 393 Assert.True(fkc.Equals(fkcDiff) == false); 394 395 //Assert.True( "Hash Code Assert.True.Failed. 1"); 396 Assert.True(fkc.GetHashCode() != fkcDiff.GetHashCode()); 397 } 398 399 [Fact] ViolationTest()400 public void ViolationTest() 401 { 402 AssertExtensions.Throws<ArgumentException>(null, () => 403 { 404 DataTable parent = _ds.Tables[0]; 405 DataTable child = _ds.Tables[1]; 406 407 parent.Rows.Add(new object[] { 1, 1, 1 }); 408 child.Rows.Add(new object[] { 2, 2, 2 }); 409 410 try 411 { 412 child.Constraints.Add(new ForeignKeyConstraint(parent.Columns[0], 413 child.Columns[0]) 414 ); 415 } 416 finally 417 { 418 // clear the rows for further testing 419 _ds.Clear(); 420 } 421 }); 422 } 423 424 [Fact] NoViolationTest()425 public void NoViolationTest() 426 { 427 DataTable parent = _ds.Tables[0]; 428 DataTable child = _ds.Tables[1]; 429 430 parent.Rows.Add(new object[] { 1, 1, 1 }); 431 child.Rows.Add(new object[] { 2, 2, 2 }); 432 433 try 434 { 435 _ds.EnforceConstraints = false; 436 child.Constraints.Add(new ForeignKeyConstraint(parent.Columns[0], 437 child.Columns[0]) 438 ); 439 } 440 finally 441 { 442 // clear the rows for further testing 443 _ds.Clear(); 444 _ds.EnforceConstraints = true; 445 } 446 } 447 448 [Fact] ModifyParentKeyBeforeAcceptChanges()449 public void ModifyParentKeyBeforeAcceptChanges() 450 { 451 DataSet ds1 = new DataSet(); 452 DataTable t1 = ds1.Tables.Add("t1"); 453 DataTable t2 = ds1.Tables.Add("t2"); 454 t1.Columns.Add("col1", typeof(int)); 455 t2.Columns.Add("col2", typeof(int)); 456 ds1.Relations.Add("fk", t1.Columns[0], t2.Columns[0]); 457 458 t1.Rows.Add(new object[] { 10 }); 459 t2.Rows.Add(new object[] { 10 }); 460 461 t1.Rows[0][0] = 20; 462 Assert.True((int)t2.Rows[0][0] == 20); 463 } 464 465 [Fact] 466 // https://bugzilla.novell.com/show_bug.cgi?id=650402 ForeignKey_650402()467 public void ForeignKey_650402() 468 { 469 DataSet data = new DataSet(); 470 DataTable parent = new DataTable("parent"); 471 DataColumn pk = parent.Columns.Add("PK"); 472 DataTable child = new DataTable("child"); 473 DataColumn fk = child.Columns.Add("FK"); 474 475 data.Tables.Add(parent); 476 data.Tables.Add(child); 477 data.Relations.Add(pk, fk); 478 479 parent.Rows.Add("value"); 480 child.Rows.Add("value"); 481 data.AcceptChanges(); 482 child.Rows[0].Delete(); 483 parent.Rows[0][0] = "value2"; 484 485 data.EnforceConstraints = false; 486 data.EnforceConstraints = true; 487 } 488 } 489 } 490