// // Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. // using System; using System.IO; using System.Text; using System.Xml; using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts; using Microsoft.SqlTools.ServiceLayer.QueryExecution.DataStorage; using Microsoft.SqlTools.ServiceLayer.UnitTests.Utility; using NUnit.Framework; namespace Microsoft.SqlTools.ServiceLayer.UnitTests.QueryExecution.DataStorage { [TestFixture] public class SaveAsXmlFileStreamWriterTests { [TestCase(false)] [TestCase(true)] public void ConstructAndDispose(bool formatted) { // Setup: Create test request and storage for the output var saveParams = new SaveResultsAsXmlRequestParams { Formatted = formatted }; var columns = Array.Empty(); var output = new byte[8192]; // If: I create and dispose of an XML file writer var xmlWriter = new SaveAsXmlFileStreamWriter(new MemoryStream(output), saveParams, columns); xmlWriter.Dispose(); // Then: // ... The output should be just the XML node and the root node var rootNode = ParseOutput(output, Encoding.UTF8); Assert.IsEmpty(rootNode.ChildNodes); // ... If the output is formatted, there should be multiple lines // otherwise, there should be only one line if (formatted) { CollectionAssert.Contains(output, (byte)'\n'); } else { CollectionAssert.DoesNotContain(output, (byte)'\n'); } } [Test] public void WriteRow_WithoutColumnSelection() { // Setup: // ... Create request params that has no selection made // ... Create a set of data to write // ... Create storage for the output var saveParams = new SaveResultsAsXmlRequestParams(); var data = new[] { new DbCellValue { DisplayValue = "item1", RawObject = "item1" }, new DbCellValue { DisplayValue = "null", RawObject = null } }; var columns = new[] { new DbColumnWrapper(new TestDbColumn("column1")), new DbColumnWrapper(new TestDbColumn("column2")) }; var output = new byte[8192]; // If: I write two rows using (var xmlWriter = new SaveAsXmlFileStreamWriter(new MemoryStream(output), saveParams, columns)) { xmlWriter.WriteRow(data, columns); xmlWriter.WriteRow(data, columns); } // Then: // ... XML should be well formed var rootNode = ParseOutput(output, Encoding.UTF8); // ... Data node should have two nodes for the two rows Assert.AreEqual(2, rootNode.ChildNodes.Count); for (int i = 0; i < 2; i++) { // ... Each row should have two nodes for the two cells var row = rootNode.ChildNodes[i]; Assert.IsNotNull(row); Assert.AreEqual(2, row.ChildNodes.Count); for (int j = 0; j < 2; j++) { var cell = row.ChildNodes[j]; Assert.IsNotNull(cell); // ... Node name should be column name Assert.AreEqual(columns[j].ColumnName, cell.Name); // ... Node value should be cell value if (data[j].RawObject == null) { Assert.IsEmpty(cell.InnerText); } else { Assert.AreEqual(data[j].DisplayValue, cell.InnerText); } } } } [Test] public void WriteRow_WithColumnSelection() { // Setup: // ... Create request params that has a selection made // ... Create a set of data to write // ... Create storage for the output var saveParams = new SaveResultsAsXmlRequestParams { ColumnEndIndex = 2, ColumnStartIndex = 1, RowEndIndex = 0, // Required for being considered a "selection" RowStartIndex = 0 }; var data = new[] { new DbCellValue { DisplayValue = "foo" }, new DbCellValue { DisplayValue = "item1", RawObject = "item1" }, new DbCellValue { DisplayValue = "null", RawObject = null }, new DbCellValue { DisplayValue = "bar" } }; var columns = new[] { new DbColumnWrapper(new TestDbColumn("ignoredCol")), new DbColumnWrapper(new TestDbColumn("column1")), new DbColumnWrapper(new TestDbColumn("column2")), new DbColumnWrapper(new TestDbColumn("ignoredCol")) }; var output = new byte[8192]; // If: I write two rows using (var xmlWriter = new SaveAsXmlFileStreamWriter(new MemoryStream(output), saveParams, columns)) { xmlWriter.WriteRow(data, columns); xmlWriter.WriteRow(data, columns); } // Then: // ... XML should be well formed var rootNode = ParseOutput(output, Encoding.UTF8); // ... Data node should have two nodes for the two rows Assert.AreEqual(2, rootNode.ChildNodes.Count); for (int i = 0; i < 2; i++) { // ... Each row should have two nodes for the two cells var row = rootNode.ChildNodes[i]; Assert.IsNotNull(row); Assert.AreEqual(2, row.ChildNodes.Count); for (int j = 0; j < 1; j++) { var cell = row.ChildNodes[j]; var columnIndex = j + 1; Assert.IsNotNull(cell); // ... Node name should be column name Assert.AreEqual(columns[columnIndex].ColumnName, cell.Name); // ... Node value should be cell value if (data[columnIndex].RawObject == null) { Assert.IsEmpty(cell.InnerText); } else { Assert.AreEqual(data[columnIndex].DisplayValue, cell.InnerText); } } } } [Test] public void WriteRow_NonDefaultEncoding() { // Setup: // ... Create request params that uses a special encoding // ... Create a set of data to write // ... Create storage for the output var saveParams = new SaveResultsAsXmlRequestParams { Encoding = "Windows-1252" }; var data = new[] { new DbCellValue { DisplayValue = "ü", RawObject = "ü" } }; var columns = new[] { new DbColumnWrapper(new TestDbColumn("column1")) }; byte[] output = new byte[8192]; // If: I write the row using (var xmlWriter = new SaveAsXmlFileStreamWriter(new MemoryStream(output), saveParams, columns)) { xmlWriter.WriteRow(data, columns); } // Then: // ... The XML file should have been written properly in windows-1252 encoding Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); var encoding = Encoding.GetEncoding("Windows-1252"); var rootNode = ParseOutput(output, encoding); // ... The umlaut should be written using Windows-1252 Assert.IsNotNull(rootNode.ChildNodes[0]); // Assert.IsNotNull(rootNode.ChildNodes[0].ChildNodes[0]); // Assert.AreEqual(rootNode.ChildNodes[0].ChildNodes[0].InnerText, "ü"); } private XmlNode ParseOutput(byte[] bytes, Encoding encoding) { var outputString = encoding.GetString(bytes) .TrimStart(encoding.GetString(encoding.Preamble).ToCharArray()) // Trim any BOM .Trim('\0'); var xmlDoc = new XmlDocument(); xmlDoc.LoadXml(outputString); // Assert: Two elements at the root, XML and the root node Assert.AreEqual(2, xmlDoc.ChildNodes.Count); Assert.AreEqual("xml", xmlDoc.ChildNodes[0]?.Name); Assert.AreEqual("data", xmlDoc.ChildNodes[1]?.Name); return xmlDoc.ChildNodes[1]; } } }