2 // Patrick Earl <mono@patearl.net>
6 // Permission is hereby granted, free of charge, to any person obtaining
7 // a copy of this software and associated documentation files (the
8 // "Software"), to deal in the Software without restriction, including
9 // without limitation the rights to use, copy, modify, merge, publish,
10 // distribute, sublicense, and/or sell copies of the Software, and to
11 // permit persons to whom the Software is furnished to do so, subject to
12 // the following conditions:
14 // The above copyright notice and this permission notice shall be
15 // included in all copies or substantial portions of the Software.
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 using System.Text.RegularExpressions;
31 using NUnit.Framework;
33 namespace MonoTests.System.Data
36 public class DataTableReadWriteXmlTest
38 public static readonly string EOL = Environment.NewLine;
40 void StandardizeXmlFormat(ref string xml)
42 XmlDocument doc = new XmlDocument();
44 StringWriter sw = new StringWriter();
49 void GenerateTestData(out DataSet ds,
50 out DataTable dtMainInDS,
51 out DataTable dtChildInDS,
54 ds = new DataSet("MyDataSet");
56 // Create a primary table and populate it with some data. Make a
57 // copy of the primary table and put it into the dataset.
58 dtMain = new DataTable("Main");
59 dtMain.Columns.Add(new DataColumn("ID", typeof(int)));
60 dtMain.Columns.Add(new DataColumn("Data", typeof(string)));
62 DataRow row = dtMain.NewRow();
67 row = dtMain.NewRow();
72 row = dtMain.NewRow();
74 row["Data"] = "Three";
77 dtMainInDS = dtMain.Copy();
78 ds.Tables.Add(dtMainInDS);
80 // Create a child table. Make a copy of the child table and put
81 // it into the dataset.
82 dtChildInDS = new DataTable("Child");
83 dtChildInDS.Columns.Add(new DataColumn("ID", typeof(int)));
84 dtChildInDS.Columns.Add(new DataColumn("PID", typeof(int)));
85 dtChildInDS.Columns.Add(new DataColumn("ChildData", typeof(string)));
87 row = dtChildInDS.NewRow();
90 row["ChildData"] = "Parent1Child1";
91 dtChildInDS.Rows.Add(row);
93 row = dtChildInDS.NewRow();
96 row["ChildData"] = "Parent1Child2";
97 dtChildInDS.Rows.Add(row);
99 row = dtChildInDS.NewRow();
102 row["ChildData"] = "Parent2Child3";
103 dtChildInDS.Rows.Add(row);
105 ds.Tables.Add(dtChildInDS);
107 // Set up the relation in the dataset.
108 ds.Relations.Add(new DataRelation("MainToChild",
109 dtMainInDS.Columns["ID"],
110 dtChildInDS.Columns["PID"]));
114 public void TestWriteXml()
117 DataTable dtMainInDS, dtChildInDS, dtMain;
119 GenerateTestData(out ds,
124 StringWriter sw = new StringWriter();
126 // Get XML for DataSet writes.
127 sw.GetStringBuilder().Length = 0;
129 string xmlDSNone = sw.ToString().Replace ("\n", EOL);
131 sw.GetStringBuilder().Length = 0;
132 ds.WriteXml(sw, XmlWriteMode.DiffGram);
133 string xmlDSDiffGram = sw.ToString().Replace ("\n", EOL);
135 sw.GetStringBuilder().Length = 0;
136 ds.WriteXml(sw, XmlWriteMode.WriteSchema);
137 string xmlDSWriteSchema = sw.ToString();
139 // Get XML for recursive DataTable writes of the same data as in
141 sw.GetStringBuilder().Length = 0;
142 dtMainInDS.WriteXml(sw, true);
143 string xmlDTNone = sw.ToString();
145 sw.GetStringBuilder().Length = 0;
146 dtMainInDS.WriteXml(sw, XmlWriteMode.DiffGram, true);
147 string xmlDTDiffGram = sw.ToString();
149 sw.GetStringBuilder().Length = 0;
150 dtMainInDS.WriteXml(sw, XmlWriteMode.WriteSchema, true);
151 string xmlDTWriteSchema = sw.ToString();
153 // The schema XML written by the DataTable call has an extra element
154 // in the element for the dataset schema definition. We remove that
155 // extra attribute and then check to see if the rest of the xml is
157 XmlDocument doc = new XmlDocument();
158 doc.LoadXml(xmlDTWriteSchema);
159 XmlNode node = doc.DocumentElement.FirstChild.FirstChild;
160 XmlAttribute a = (XmlAttribute)node.Attributes.GetNamedItem("msdata:MainDataTable");
161 Assert.IsNotNull(a, "Test#01");
162 Assert.AreEqual("Main", a.Value, "Test#02");
164 node.Attributes.Remove(a);
165 sw.GetStringBuilder().Length = 0;
167 xmlDTWriteSchema = sw.ToString();
169 StandardizeXmlFormat(ref xmlDSWriteSchema);
171 Assert.AreEqual(xmlDSNone, xmlDTNone, "Test#03");
172 Assert.AreEqual(xmlDSDiffGram, xmlDTDiffGram, "Test#04");
173 Assert.IsTrue (xmlDSWriteSchema.IndexOf ("UseCurrentLocale") > 0, "Test#05-premise1");
174 Assert.AreEqual(xmlDSWriteSchema, xmlDTWriteSchema, "Test#05");
176 // Now that we've tested writing tables (including children),
177 // we will go on to test the cases where the hierarchy flag
178 // is false. For this, we will test one table inside the
179 // dataset and one table outside the dataset.
181 // First, we fix our test DataSet to only have a single table
182 // with no relations. Then, we go about comparing the XML.
183 // Get XML for DataSet writes.
184 ds.Tables[1].Constraints.Remove(ds.Tables[1].Constraints[0]);
185 ds.Tables[0].Constraints.Remove(ds.Tables[0].Constraints[0]);
186 ds.Tables[0].ChildRelations.Remove("MainToChild");
187 ds.Tables.Remove("Child");
189 sw.GetStringBuilder().Length = 0;
191 xmlDSNone = sw.ToString().Replace ("\n", EOL);
193 sw.GetStringBuilder().Length = 0;
194 ds.WriteXml(sw, XmlWriteMode.DiffGram);
195 xmlDSDiffGram = sw.ToString().Replace ("\n", EOL);
197 sw.GetStringBuilder().Length = 0;
198 ds.WriteXml(sw, XmlWriteMode.WriteSchema);
199 xmlDSWriteSchema = sw.ToString();
201 // Get all the DataTable.WriteXml results.
202 sw.GetStringBuilder().Length = 0;
203 dtMainInDS.WriteXml(sw);
204 string xmlDTNoneInDS = sw.ToString();
206 sw.GetStringBuilder().Length = 0;
207 dtMainInDS.WriteXml(sw, XmlWriteMode.DiffGram);
208 string xmlDTDiffGramInDS = sw.ToString();
210 sw.GetStringBuilder().Length = 0;
211 dtMainInDS.WriteXml(sw, XmlWriteMode.WriteSchema);
212 string xmlDTWriteSchemaInDS = sw.ToString();
214 sw.GetStringBuilder().Length = 0;
216 string xmlDTNoneNoDS = sw.ToString();
218 sw.GetStringBuilder().Length = 0;
219 dtMain.WriteXml(sw, XmlWriteMode.DiffGram);
220 string xmlDTDiffGramNoDS = sw.ToString();
222 sw.GetStringBuilder().Length = 0;
223 dtMain.WriteXml(sw, XmlWriteMode.WriteSchema);
224 string xmlDTWriteSchemaNoDS = sw.ToString();
226 Assert.AreEqual(xmlDSNone, xmlDTNoneInDS, "Test#06");
228 // The only difference between the xml output from inside the
229 // dataset and the xml output from outside the dataset is that
230 // there's a fake <DocumentElement> tag surrounding tbe table
231 // in the second case. We replace it with the name of the
232 // dataset for testing purposes.
233 doc.LoadXml(xmlDTNoneNoDS);
234 Assert.AreEqual("DocumentElement", doc.DocumentElement.Name, "Test#07");
235 sw.GetStringBuilder().Length = 0;
237 xmlDTNoneNoDS = sw.ToString();
238 xmlDTNoneNoDS = xmlDTNoneNoDS.Replace("<DocumentElement>", "<MyDataSet>");
239 xmlDTNoneNoDS = xmlDTNoneNoDS.Replace("</DocumentElement>", "</MyDataSet>");
241 StandardizeXmlFormat(ref xmlDSNone);
243 Assert.AreEqual(xmlDSNone, xmlDTNoneNoDS, "Test#08");
245 // Now check the DiffGram.
246 Assert.AreEqual(xmlDSDiffGram, xmlDTDiffGramInDS, "Test#09");
248 doc.LoadXml(xmlDTDiffGramNoDS);
249 Assert.AreEqual("DocumentElement", doc.DocumentElement.FirstChild.Name, "Test#10");
250 xmlDTDiffGramNoDS = xmlDTDiffGramNoDS.Replace("<DocumentElement>", "<MyDataSet>");
251 xmlDTDiffGramNoDS = xmlDTDiffGramNoDS.Replace("</DocumentElement>", "</MyDataSet>");
253 Assert.AreEqual(xmlDSDiffGram, xmlDTDiffGramNoDS, "Test#11");
255 // Finally we check the WriteSchema version of the data. First
256 // we remove the extra "msdata:MainDataTable" attribute from
257 // the schema declaration part of the DataTable xml.
258 doc = new XmlDocument();
259 doc.LoadXml(xmlDTWriteSchemaInDS);
260 node = doc.DocumentElement.FirstChild.FirstChild;
261 a = (XmlAttribute)node.Attributes.GetNamedItem("msdata:MainDataTable");
262 Assert.IsNotNull(a, "Test#12");
263 Assert.AreEqual("Main", a.Value, "Test#13");
264 node.Attributes.Remove(a);
265 sw.GetStringBuilder().Length = 0;
267 xmlDTWriteSchemaInDS = sw.ToString();
269 StandardizeXmlFormat(ref xmlDSWriteSchema);
271 Assert.AreEqual(xmlDSWriteSchema, xmlDTWriteSchemaInDS, "Test#14");
273 // Remove the extra "msdata:MainDataTable" for the other test case.
274 // Also make sure we have "NewDataSet" in the appropriate locations.
275 doc = new XmlDocument();
276 doc.LoadXml(xmlDTWriteSchemaNoDS);
277 node = doc.DocumentElement.FirstChild.FirstChild;
278 a = (XmlAttribute)node.Attributes.GetNamedItem("msdata:MainDataTable");
279 Assert.IsNotNull(a, "Test#15");
280 Assert.AreEqual("Main", a.Value, "Test#16");
281 node.Attributes.Remove(a);
282 sw.GetStringBuilder().Length = 0;
285 Assert.AreEqual("NewDataSet", doc.DocumentElement.Name, "Test#17");
286 Assert.AreEqual("NewDataSet", doc.DocumentElement.FirstChild.Attributes["id"].Value, "Test#18");
287 Assert.AreEqual("NewDataSet", doc.DocumentElement.FirstChild.FirstChild.Attributes["name"].Value, "Test#19");
289 xmlDTWriteSchemaNoDS = sw.ToString();
291 xmlDTWriteSchemaNoDS = xmlDTWriteSchemaNoDS.Replace("<NewDataSet>","<MyDataSet>");
292 xmlDTWriteSchemaNoDS = xmlDTWriteSchemaNoDS.Replace("</NewDataSet>","</MyDataSet>");
293 xmlDTWriteSchemaNoDS = xmlDTWriteSchemaNoDS.Replace("\"NewDataSet\"","\"MyDataSet\"");
295 Assert.AreEqual(xmlDSWriteSchema, xmlDTWriteSchemaNoDS, "Test#20");
299 public void TestReadXml()
301 // For reading, DataTable.ReadXml only supports reading in xml with
302 // the schema included. This means that we can only read in XML
303 // that was generated with the WriteSchema flag.
305 DataTable dtMainInDS, dtChildInDS, dtMain;
307 GenerateTestData(out ds,
312 StringWriter sw = new StringWriter();
314 // Get XML for recursive DataTable writes of the same data as in
316 sw.GetStringBuilder().Length = 0;
317 dtMainInDS.WriteXml(sw, true);
318 string xmlDTNone = sw.ToString();
320 sw.GetStringBuilder().Length = 0;
321 dtMainInDS.WriteXml(sw, XmlWriteMode.DiffGram, true);
322 string xmlDTDiffGram = sw.ToString();
324 sw.GetStringBuilder().Length = 0;
325 dtMainInDS.WriteXml(sw, XmlWriteMode.WriteSchema, true);
326 string xmlMultiTable = sw.ToString();
328 sw.GetStringBuilder().Length = 0;
329 dtMain.WriteXml(sw, XmlWriteMode.WriteSchema);
330 string xmlSingleTable = sw.ToString();
332 DataTable newdt = new DataTable();
335 newdt.ReadXml(new StringReader(xmlDTNone));
336 Assert.Fail("Test#01");
337 } catch(InvalidOperationException) {
338 // DataTable does not support schema inference from Xml.
342 newdt.ReadXml(new StringReader(xmlDTDiffGram));
343 Assert.Fail("Test#02");
344 } catch(InvalidOperationException) {
345 // DataTable does not support schema inference from Xml.
348 DataTable multiTable = new DataTable();
349 multiTable.ReadXml(new StringReader(xmlMultiTable));
350 // Do some simple checks to see if the main dataset was created
351 // and if there are relationships present.
352 Assert.AreEqual("MyDataSet", multiTable.DataSet.DataSetName, "Test#03");
353 Assert.AreEqual(1, multiTable.ChildRelations.Count, "Test#04");
354 Assert.AreEqual(1, multiTable.Constraints.Count, "Test#05");
355 // Write the table back out and check to see that the XML is
356 // the same as before.
357 sw.GetStringBuilder().Length = 0;
358 multiTable.WriteXml(sw, XmlWriteMode.WriteSchema, true);
359 string xmlMultiTableCheck = sw.ToString();
360 Assert.IsTrue (xmlMultiTable.IndexOf ("UseCurrentLocale") > 0, "Test#06-premise1");
361 Assert.IsTrue (xmlMultiTable.IndexOf ("keyref") > 0, "Test#06-premise2");
362 Assert.AreEqual(xmlMultiTable, xmlMultiTableCheck, "Test#06");
364 DataTable singleTable = new DataTable();
365 singleTable.ReadXml(new StringReader(xmlSingleTable));
366 // Do some simple checks on the table.
367 Assert.IsNull(singleTable.DataSet, "Test#07");
368 Assert.AreEqual("Main", singleTable.TableName, "Test#08");
369 // Write the table out and check if it's the same.
370 sw.GetStringBuilder().Length = 0;
371 singleTable.WriteXml(sw, XmlWriteMode.WriteSchema);
372 string xmlSingleTableCheck = sw.ToString();
373 Assert.AreEqual(xmlSingleTable, xmlSingleTableCheck, "Test#09");