diff --git a/csharp-intermediate-topics/DataTableOverview/DataTableOverview/DataTableOverview.csproj b/csharp-intermediate-topics/DataTableOverview/DataTableOverview/DataTableOverview.csproj
index 48284b519e..1bf2c3bf8b 100644
--- a/csharp-intermediate-topics/DataTableOverview/DataTableOverview/DataTableOverview.csproj
+++ b/csharp-intermediate-topics/DataTableOverview/DataTableOverview/DataTableOverview.csproj
@@ -2,14 +2,11 @@
Exe
- net7.0
+ net10.0
enable
enable
-
-
-
PreserveNewest
diff --git a/csharp-intermediate-topics/DataTableOverview/DataTableOverview/Program.cs b/csharp-intermediate-topics/DataTableOverview/DataTableOverview/Program.cs
index 87ae8054ad..2e21b00cbb 100644
--- a/csharp-intermediate-topics/DataTableOverview/DataTableOverview/Program.cs
+++ b/csharp-intermediate-topics/DataTableOverview/DataTableOverview/Program.cs
@@ -9,10 +9,12 @@ public static void Main(string[] args)
var dt = CreateMainDataTable();
PopulateDataTable(dt);
+ AddPrimaryKey(dt);
+ PrintConstraints(dt);
PrintData(dt);
DataTable dtClone = dt.Clone();
- PrintColumns(dtClone);
+ PrintColumns(dtClone);
DataTable dtCopy = dt.Copy();
PrintData(dtCopy);
@@ -20,6 +22,8 @@ public static void Main(string[] args)
AddNewRow(dt);
FilterDataTable(dt);
+ PrintTable(dt);
+
SalesDataProcessor.ProcessSales();
}
@@ -32,45 +36,41 @@ public static DataTable CreateMainDataTable()
dt.Columns.Add("Date", typeof(DateTime));
dt.Columns.Add("Price", typeof(double));
- // add primary key
- var pkCol = new DataColumn("Key", typeof(int));
- dt.Columns.Add(pkCol);
-
- var pkCols = new DataColumn[1];
- pkCols[0] = pkCol;
-
- dt.PrimaryKey = pkCols;
-
return dt;
}
public static void PopulateDataTable(DataTable dt)
{
- // add row
// 1) declare and instantiate row
- DataRow row;
- row = dt.NewRow();
+ DataRow row = dt.NewRow();
// 2) set column values
row["Ticker"] = "MSFT";
row["Date"] = new DateTime(2023, 3, 3);
- row["Price"] = 255.29;
- row["Key"] = 0;
+ row["Price"] = 255.29;
// by Ordinal/index
row[0] = "MSFT";
row[1] = new DateTime(2023, 3, 3);
row[2] = 255.29;
- row[3] = 0;
// 3) add populated row to table
dt.Rows.Add(row);
}
+ public static void AddPrimaryKey(DataTable dt)
+ {
+ var pkCol = new DataColumn("Key", typeof(int));
+ dt.Columns.Add(pkCol);
+
+ dt.Rows[0]["Key"] = 0;
+
+ dt.PrimaryKey = [pkCol];
+ }
+
public static void AddNewRow(DataTable dt)
{
- DataRow row;
- row = dt.NewRow();
+ DataRow row = dt.NewRow();
row["Ticker"] = "AMZN";
row["Date"] = new DateTime(2023, 3, 6);
@@ -80,6 +80,11 @@ public static void AddNewRow(DataTable dt)
dt.Rows.Add(row);
}
+ public static void AddNewRowFromValues(DataTable dt)
+ {
+ dt.Rows.Add("AMZN", new DateTime(2023, 3, 6), 93.75, 1);
+ }
+
public static void PrintConstraints(DataTable dt)
{
foreach (Constraint constraint in dt.Constraints)
@@ -124,5 +129,21 @@ public static void PrintData(DataTable dt)
}
}
}
+
+ public static void PrintTable(DataTable dt)
+ {
+ var header = dt.Columns.Cast().Select(col => col.ColumnName);
+ Console.WriteLine(string.Join(" | ", header));
+
+ foreach (DataRow row in dt.Rows)
+ Console.WriteLine(string.Join(" | ", row.ItemArray));
+ }
+
+ public static IEnumerable GetTickersBelow(DataTable dt, double price)
+ {
+ return dt.AsEnumerable()
+ .Where(row => row.Field("Price") < price)
+ .Select(row => row.Field("Ticker"));
+ }
}
-}
\ No newline at end of file
+}
diff --git a/csharp-intermediate-topics/DataTableOverview/DataTableOverview/SalesDataProcessor.cs b/csharp-intermediate-topics/DataTableOverview/DataTableOverview/SalesDataProcessor.cs
index 15c93de76d..627081d66f 100644
--- a/csharp-intermediate-topics/DataTableOverview/DataTableOverview/SalesDataProcessor.cs
+++ b/csharp-intermediate-topics/DataTableOverview/DataTableOverview/SalesDataProcessor.cs
@@ -16,21 +16,21 @@ public static void ProcessSales()
public static DataTable CsvToDataTable(string filePath)
{
- DataTable dtRes = new DataTable();
+ var dtRes = new DataTable();
using (var parser = new TextFieldParser(filePath))
{
parser.TextFieldType = FieldType.Delimited;
parser.TrimWhiteSpace = true;
parser.SetDelimiters(",");
- var columns = parser.ReadFields();
+ var columns = parser.ReadFields() ?? [];
foreach (var col in columns)
dtRes.Columns.Add(col);
while (!parser.EndOfData)
{
- var row = parser.ReadFields();
+ var row = parser.ReadFields() ?? [];
dtRes.LoadDataRow(row, true);
}
}
diff --git a/csharp-intermediate-topics/DataTableOverview/DataTableOverview/vegetable-sales.csv b/csharp-intermediate-topics/DataTableOverview/DataTableOverview/vegetable-sales.csv
index 3842b2ebbf..6f622e0a21 100644
--- a/csharp-intermediate-topics/DataTableOverview/DataTableOverview/vegetable-sales.csv
+++ b/csharp-intermediate-topics/DataTableOverview/DataTableOverview/vegetable-sales.csv
@@ -5,7 +5,7 @@ Pepper,2,2,4
Cucumber,4,1,4
Lettuce,6,0.5,3
Asparagus,2,2.5,5
-Carrot,1,3,1
+Carrot,1,3,3
Broccoli,2,0.75,1.5
Pepper,4,2,8
Cucumber,7,1,7
diff --git a/csharp-intermediate-topics/DataTableOverview/Tests/ProgramTests.cs b/csharp-intermediate-topics/DataTableOverview/Tests/ProgramTests.cs
index 38216d363e..05499fef7c 100644
--- a/csharp-intermediate-topics/DataTableOverview/Tests/ProgramTests.cs
+++ b/csharp-intermediate-topics/DataTableOverview/Tests/ProgramTests.cs
@@ -5,13 +5,23 @@
namespace Tests
{
+ [Collection("Console output")]
public class ProgramTests
{
+ private static DataTable CreateKeyedTable()
+ {
+ var dt = Program.CreateMainDataTable();
+ Program.PopulateDataTable(dt);
+ Program.AddPrimaryKey(dt);
+
+ return dt;
+ }
+
[Fact]
public static void WhenCreateMainDataTable_ThenColumnsPopulateCorrectly()
{
var dt = Program.CreateMainDataTable();
- var expectedColumns = new string[] { "Ticker", "Date", "Price", "Key" };
+ var expectedColumns = new string[] { "Ticker", "Date", "Price" };
var actualColumns = dt.Columns.Cast()
.Select(x => x.ColumnName)
@@ -21,13 +31,25 @@ public static void WhenCreateMainDataTable_ThenColumnsPopulateCorrectly()
}
[Fact]
- public static void WhenCreateMaindataTable_ThenPrimaryKeyEqualsKey()
+ public static void WhenAddPrimaryKey_ThenPrimaryKeyEqualsKey()
{
- var dt = Program.CreateMainDataTable();
+ var dt = CreateKeyedTable();
var pkActual = dt.PrimaryKey;
Assert.Equal("Key", pkActual[0].Caption);
+ Assert.Equal(0, dt.Rows[0]["Key"]);
+ }
+
+ [Fact]
+ public static void WhenPrimaryKeySetOnColumnWithEmptyValues_ThenDataExceptionThrown()
+ {
+ var dt = Program.CreateMainDataTable();
+ Program.PopulateDataTable(dt);
+ var pkCol = new DataColumn("Key", typeof(int));
+ dt.Columns.Add(pkCol);
+
+ Assert.Throws(() => dt.PrimaryKey = [pkCol]);
}
[Fact]
@@ -43,17 +65,36 @@ public static void WhenPopulateDataTable_ThenDataTableContainsMsftRecord()
[Fact]
public static void WhenAddNewRow_ThenDataTableContainsAmznRecord()
{
- var dt = Program.CreateMainDataTable();
+ var dt = CreateKeyedTable();
Program.AddNewRow(dt);
- Assert.Contains("AMZN", Convert.ToString(dt.Rows[0][0]));
+ Assert.Contains("AMZN", Convert.ToString(dt.Rows[1][0]));
+ }
+
+ [Fact]
+ public static void WhenAddNewRowFromValues_ThenDataTableContainsAmznRecord()
+ {
+ var dt = CreateKeyedTable();
+
+ Program.AddNewRowFromValues(dt);
+
+ Assert.Equal("AMZN", dt.Rows[1]["Ticker"]);
+ Assert.Equal(1, dt.Rows[1]["Key"]);
+ }
+
+ [Fact]
+ public static void WhenRowAddedWithDuplicateKey_ThenConstraintExceptionThrown()
+ {
+ var dt = CreateKeyedTable();
+
+ Assert.Throws(() => dt.Rows.Add("AMZN", new DateTime(2023, 3, 6), 93.75, 0));
}
[Fact]
public static void WhenPrintConstraints_ThenReturnsConstraintOneUniqueConstraint()
{
- var dt = Program.CreateMainDataTable();
+ var dt = CreateKeyedTable();
var stringWriter = new StringWriter();
Console.SetOut(stringWriter);
@@ -65,10 +106,21 @@ public static void WhenPrintConstraints_ThenReturnsConstraintOneUniqueConstraint
Assert.Contains("System.Data.UniqueConstraint", output);
}
+ [Fact]
+ public static void WhenCloneCalled_ThenAllColumnsAndNoRowsCopied()
+ {
+ var dt = CreateKeyedTable();
+
+ var dtClone = dt.Clone();
+
+ Assert.Equal(4, dtClone.Columns.Count);
+ Assert.Empty(dtClone.Rows);
+ }
+
[Fact]
public static void WhenFilterDataTable_ThenPrintsAmznDataRow()
{
- var dt = Program.CreateMainDataTable();
+ var dt = CreateKeyedTable();
Program.AddNewRow(dt);
var stringWriter = new StringWriter();
@@ -78,13 +130,13 @@ public static void WhenFilterDataTable_ThenPrintsAmznDataRow()
var output = stringWriter.ToString();
Assert.Contains("AMZN", output);
+ Assert.DoesNotContain("MSFT", output);
}
[Fact]
public static void WhenPrintData_ThenPrintsExpectedData()
{
- var dt = Program.CreateMainDataTable();
- Program.PopulateDataTable(dt);
+ var dt = CreateKeyedTable();
var stringWriter = new StringWriter();
Console.SetOut(stringWriter);
@@ -95,7 +147,35 @@ public static void WhenPrintData_ThenPrintsExpectedData()
Assert.Contains("MSFT", output);
Assert.Contains(Convert.ToString(new DateTime(2023, 3, 3)), output);
Assert.Contains("255.29", output);
- Assert.Contains("0", output);
+ Assert.Contains("Key: 0", output);
+ }
+
+ [Fact]
+ public static void WhenPrintTable_ThenPrintsHeaderAndOneLinePerRow()
+ {
+ var dt = CreateKeyedTable();
+ Program.AddNewRow(dt);
+
+ var stringWriter = new StringWriter();
+ Console.SetOut(stringWriter);
+
+ Program.PrintTable(dt);
+ var lines = stringWriter.ToString().Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries);
+
+ Assert.Equal("Ticker | Date | Price | Key", lines[0]);
+ Assert.Equal(3, lines.Length);
+ Assert.StartsWith("AMZN | ", lines[2]);
+ }
+
+ [Fact]
+ public static void WhenGetTickersBelow_ThenReturnsOnlyCheaperTickers()
+ {
+ var dt = CreateKeyedTable();
+ Program.AddNewRow(dt);
+
+ var tickers = Program.GetTickersBelow(dt, 100);
+
+ Assert.Equal(new[] { "AMZN" }, tickers);
}
}
-}
\ No newline at end of file
+}
diff --git a/csharp-intermediate-topics/DataTableOverview/Tests/SalesDataProcessorTests.cs b/csharp-intermediate-topics/DataTableOverview/Tests/SalesDataProcessorTests.cs
index 0fd8f6d3d5..a9d1a8f9e7 100644
--- a/csharp-intermediate-topics/DataTableOverview/Tests/SalesDataProcessorTests.cs
+++ b/csharp-intermediate-topics/DataTableOverview/Tests/SalesDataProcessorTests.cs
@@ -1,10 +1,10 @@
using DataTableOverview;
-using Microsoft.VisualStudio.TestPlatform.TestHost;
using Xunit;
using System;
namespace Tests
{
+ [Collection("Console output")]
public class SalesDataProcessorTests
{
[Fact]
@@ -32,6 +32,15 @@ public void WhenProcessSales_ThenPrintsSelectedRows()
Assert.Contains("Carrot", output);
}
+
+ [Fact]
+ public void WhenNumericFilterRunsOnCsvColumn_ThenEvaluateExceptionThrown()
+ {
+ var filePath = AppDomain.CurrentDomain.BaseDirectory + "vegetable-sales.csv";
+ var veggieSales = SalesDataProcessor.CsvToDataTable(filePath);
+
+ Assert.Equal(typeof(string), veggieSales.Columns["Price"]!.DataType);
+ Assert.Throws(() => veggieSales.Select("Price > 1"));
+ }
}
}
-
diff --git a/csharp-intermediate-topics/DataTableOverview/Tests/Tests.csproj b/csharp-intermediate-topics/DataTableOverview/Tests/Tests.csproj
index f805d3f2a2..3cd329e537 100644
--- a/csharp-intermediate-topics/DataTableOverview/Tests/Tests.csproj
+++ b/csharp-intermediate-topics/DataTableOverview/Tests/Tests.csproj
@@ -1,7 +1,7 @@
- net7.0
+ net10.0
enable
enable
@@ -9,13 +9,13 @@
-
-
-
+
+
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all