From 8801e407f266c7f584e05a5d3099e015764351a7 Mon Sep 17 00:00:00 2001 From: Prashanth Govindarajan Date: Fri, 4 Jun 2021 15:40:25 -0700 Subject: [PATCH] Dataframe csv datetime (#5834) * Give message with line and column of CSV file if data conversion fails * Allow parsing of DateTime data in CSV import * Delete query.json * Address comments * Verify contents on date column * Change to a sample date Co-authored-by: Derek Diamond --- src/Microsoft.Data.Analysis/DataFrame.IO.cs | 13 + src/Microsoft.Data.Analysis/DataFrame.cs | 1 + .../DateTimeComputation.cs | 314 ++++++++++++++++++ .../PrimitiveDataFrameColumnComputations.cs | 5 + .../PrimitiveDataFrameColumnComputations.tt | 5 + .../DataFrame.IOTests.cs | 81 +++++ .../DataFrameTests.cs | 177 ++++++++++ 7 files changed, 596 insertions(+) create mode 100644 src/Microsoft.Data.Analysis/DateTimeComputation.cs diff --git a/src/Microsoft.Data.Analysis/DataFrame.IO.cs b/src/Microsoft.Data.Analysis/DataFrame.IO.cs index 1d39d08258..1253ed6149 100644 --- a/src/Microsoft.Data.Analysis/DataFrame.IO.cs +++ b/src/Microsoft.Data.Analysis/DataFrame.IO.cs @@ -47,6 +47,13 @@ private static Type GuessKind(int col, List read) ++nbline; continue; } + bool dateParse = DateTime.TryParse(val, out DateTime dateResult); + if (dateParse) + { + res = DetermineType(nbline == 0, typeof(DateTime), res); + ++nbline; + continue; + } res = DetermineType(nbline == 0, typeof(string), res); ++nbline; @@ -71,6 +78,8 @@ private static Type MaxKind(Type a, Type b) return typeof(float); if (a == typeof(bool) || b == typeof(bool)) return typeof(bool); + if (a == typeof(DateTime) || b == typeof(DateTime)) + return typeof(DateTime); return typeof(string); } @@ -165,6 +174,10 @@ private static DataFrameColumn CreateColumn(Type kind, string[] columnNames, int { ret = new UInt16DataFrameColumn(GetColumnName(columnNames, columnIndex)); } + else if (kind == typeof(DateTime)) + { + ret = new PrimitiveDataFrameColumn(GetColumnName(columnNames, columnIndex)); + } else { throw new NotSupportedException(nameof(kind)); diff --git a/src/Microsoft.Data.Analysis/DataFrame.cs b/src/Microsoft.Data.Analysis/DataFrame.cs index b3e04bf7b6..9c1a68787e 100644 --- a/src/Microsoft.Data.Analysis/DataFrame.cs +++ b/src/Microsoft.Data.Analysis/DataFrame.cs @@ -531,6 +531,7 @@ public DataFrame Append(IEnumerable row = null, bool inPlace = false) if (value != null) { value = Convert.ChangeType(value, column.DataType); + if (value is null) { throw new ArgumentException(string.Format(Strings.MismatchedValueType, column.DataType), value.GetType().ToString()); diff --git a/src/Microsoft.Data.Analysis/DateTimeComputation.cs b/src/Microsoft.Data.Analysis/DateTimeComputation.cs new file mode 100644 index 0000000000..5335d30f87 --- /dev/null +++ b/src/Microsoft.Data.Analysis/DateTimeComputation.cs @@ -0,0 +1,314 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Microsoft.Data.Analysis +{ + internal class DateTimeComputation : IPrimitiveColumnComputation + { + public void Abs(PrimitiveColumnContainer column) + { + throw new NotSupportedException(); + } + + public void All(PrimitiveColumnContainer column, out bool ret) + { + throw new NotSupportedException(); + } + + public void Any(PrimitiveColumnContainer column, out bool ret) + { + throw new NotSupportedException(); + } + + public void CumulativeMax(PrimitiveColumnContainer column) + { + var ret = column.Buffers[0].ReadOnlySpan[0]; + for (int b = 0; b < column.Buffers.Count; b++) + { + var buffer = column.Buffers[b]; + var mutableBuffer = DataFrameBuffer.GetMutableBuffer(buffer); + var mutableSpan = mutableBuffer.Span; + var readOnlySpan = buffer.ReadOnlySpan; + for (int i = 0; i < readOnlySpan.Length; i++) + { + var val = readOnlySpan[i]; + + if (val > ret) + { + ret = val; + } + + mutableSpan[i] = ret; + } + column.Buffers[b] = mutableBuffer; + } + } + + public void CumulativeMax(PrimitiveColumnContainer column, IEnumerable rows) + { + var ret = default(DateTime); + var mutableBuffer = DataFrameBuffer.GetMutableBuffer(column.Buffers[0]); + var span = mutableBuffer.Span; + long minRange = 0; + long maxRange = ReadOnlyDataFrameBuffer.MaxCapacity; + long maxCapacity = maxRange; + IEnumerator enumerator = rows.GetEnumerator(); + if (enumerator.MoveNext()) + { + long row = enumerator.Current; + if (row < minRange || row >= maxRange) + { + int bufferIndex = (int)(row / maxCapacity); + mutableBuffer = DataFrameBuffer.GetMutableBuffer(column.Buffers[bufferIndex]); + span = mutableBuffer.Span; + minRange = checked(bufferIndex * maxCapacity); + maxRange = checked((bufferIndex + 1) * maxCapacity); + } + row -= minRange; + ret = span[(int)row]; + } + + while (enumerator.MoveNext()) + { + long row = enumerator.Current; + if (row < minRange || row >= maxRange) + { + int bufferIndex = (int)(row / maxCapacity); + mutableBuffer = DataFrameBuffer.GetMutableBuffer(column.Buffers[bufferIndex]); + span = mutableBuffer.Span; + minRange = checked(bufferIndex * maxCapacity); + maxRange = checked((bufferIndex + 1) * maxCapacity); + } + row -= minRange; + + var val = span[(int)row]; + + if (val > ret) + { + ret = val; + } + + span[(int)row] = ret; + } + } + + public void CumulativeMin(PrimitiveColumnContainer column) + { + var ret = column.Buffers[0].ReadOnlySpan[0]; + for (int b = 0; b < column.Buffers.Count; b++) + { + var buffer = column.Buffers[b]; + var mutableBuffer = DataFrameBuffer.GetMutableBuffer(buffer); + var mutableSpan = mutableBuffer.Span; + var readOnlySpan = buffer.ReadOnlySpan; + for (int i = 0; i < readOnlySpan.Length; i++) + { + var val = readOnlySpan[i]; + + if (val < ret) + { + ret = val; + } + + mutableSpan[i] = ret; + } + column.Buffers[b] = mutableBuffer; + } + } + + public void CumulativeMin(PrimitiveColumnContainer column, IEnumerable rows) + { + var ret = default(DateTime); + var mutableBuffer = DataFrameBuffer.GetMutableBuffer(column.Buffers[0]); + var span = mutableBuffer.Span; + long minRange = 0; + long maxRange = ReadOnlyDataFrameBuffer.MaxCapacity; + long maxCapacity = maxRange; + IEnumerator enumerator = rows.GetEnumerator(); + if (enumerator.MoveNext()) + { + long row = enumerator.Current; + if (row < minRange || row >= maxRange) + { + int bufferIndex = (int)(row / maxCapacity); + mutableBuffer = DataFrameBuffer.GetMutableBuffer(column.Buffers[bufferIndex]); + span = mutableBuffer.Span; + minRange = checked(bufferIndex * maxCapacity); + maxRange = checked((bufferIndex + 1) * maxCapacity); + } + row -= minRange; + ret = span[(int)row]; + } + + while (enumerator.MoveNext()) + { + long row = enumerator.Current; + if (row < minRange || row >= maxRange) + { + int bufferIndex = (int)(row / maxCapacity); + mutableBuffer = DataFrameBuffer.GetMutableBuffer(column.Buffers[bufferIndex]); + span = mutableBuffer.Span; + minRange = checked(bufferIndex * maxCapacity); + maxRange = checked((bufferIndex + 1) * maxCapacity); + } + row -= minRange; + + var val = span[(int)row]; + + if (val < ret) + { + ret = val; + } + + span[(int)row] = ret; + } + } + + public void CumulativeProduct(PrimitiveColumnContainer column) + { + throw new NotSupportedException(); + } + + public void CumulativeProduct(PrimitiveColumnContainer column, IEnumerable rows) + { + throw new NotSupportedException(); + } + + public void CumulativeSum(PrimitiveColumnContainer column) + { + throw new NotSupportedException(); + } + + public void CumulativeSum(PrimitiveColumnContainer column, IEnumerable rows) + { + throw new NotSupportedException(); + } + + public void Max(PrimitiveColumnContainer column, out DateTime ret) + { + ret = column.Buffers[0].ReadOnlySpan[0]; + for (int b = 0; b < column.Buffers.Count; b++) + { + var buffer = column.Buffers[b]; + var readOnlySpan = buffer.ReadOnlySpan; + for (int i = 0; i < readOnlySpan.Length; i++) + { + var val = readOnlySpan[i]; + + if (val > ret) + { + ret = val; + } + } + } + } + + public void Max(PrimitiveColumnContainer column, IEnumerable rows, out DateTime ret) + { + ret = default; + var readOnlySpan = column.Buffers[0].ReadOnlySpan; + long minRange = 0; + long maxRange = ReadOnlyDataFrameBuffer.MaxCapacity; + long maxCapacity = maxRange; + IEnumerator enumerator = rows.GetEnumerator(); + while (enumerator.MoveNext()) + { + long row = enumerator.Current; + if (row < minRange || row >= maxRange) + { + int bufferIndex = (int)(row / maxCapacity); + readOnlySpan = column.Buffers[bufferIndex].ReadOnlySpan; + minRange = checked(bufferIndex * maxCapacity); + maxRange = checked((bufferIndex + 1) * maxCapacity); + } + row -= minRange; + + var val = readOnlySpan[(int)row]; + + if (val > ret) + { + ret = val; + } + } + } + + public void Min(PrimitiveColumnContainer column, out DateTime ret) + { + ret = column.Buffers[0].ReadOnlySpan[0]; + for (int b = 0; b < column.Buffers.Count; b++) + { + var buffer = column.Buffers[b]; + var readOnlySpan = buffer.ReadOnlySpan; + for (int i = 0; i < readOnlySpan.Length; i++) + { + var val = readOnlySpan[i]; + + if (val < ret) + { + ret = val; + } + } + } + } + + public void Min(PrimitiveColumnContainer column, IEnumerable rows, out DateTime ret) + { + ret = default; + var readOnlySpan = column.Buffers[0].ReadOnlySpan; + long minRange = 0; + long maxRange = ReadOnlyDataFrameBuffer.MaxCapacity; + long maxCapacity = maxRange; + IEnumerator enumerator = rows.GetEnumerator(); + while (enumerator.MoveNext()) + { + long row = enumerator.Current; + if (row < minRange || row >= maxRange) + { + int bufferIndex = (int)(row / maxCapacity); + readOnlySpan = column.Buffers[bufferIndex].ReadOnlySpan; + minRange = checked(bufferIndex * maxCapacity); + maxRange = checked((bufferIndex + 1) * maxCapacity); + } + row -= minRange; + + var val = readOnlySpan[(int)row]; + + if (val < ret) + { + ret = val; + } + } + } + + public void Product(PrimitiveColumnContainer column, out DateTime ret) + { + throw new NotSupportedException(); + } + + public void Product(PrimitiveColumnContainer column, IEnumerable rows, out DateTime ret) + { + throw new NotSupportedException(); + } + + public void Sum(PrimitiveColumnContainer column, out DateTime ret) + { + throw new NotSupportedException(); + } + + public void Sum(PrimitiveColumnContainer column, IEnumerable rows, out DateTime ret) + { + throw new NotSupportedException(); + } + + public void Round(PrimitiveColumnContainer column) + { + throw new NotSupportedException(); + } + + } +} diff --git a/src/Microsoft.Data.Analysis/PrimitiveDataFrameColumnComputations.cs b/src/Microsoft.Data.Analysis/PrimitiveDataFrameColumnComputations.cs index 987209fa1a..fd93fd231e 100644 --- a/src/Microsoft.Data.Analysis/PrimitiveDataFrameColumnComputations.cs +++ b/src/Microsoft.Data.Analysis/PrimitiveDataFrameColumnComputations.cs @@ -99,6 +99,11 @@ public static IPrimitiveColumnComputation GetComputation() { return (IPrimitiveColumnComputation)new UShortComputation(); } + else if (typeof(T) == typeof(DateTime)) + { + return (IPrimitiveColumnComputation)new DateTimeComputation(); + } + throw new NotSupportedException(); } } diff --git a/src/Microsoft.Data.Analysis/PrimitiveDataFrameColumnComputations.tt b/src/Microsoft.Data.Analysis/PrimitiveDataFrameColumnComputations.tt index a2f82a8c2f..85a78cf1ed 100644 --- a/src/Microsoft.Data.Analysis/PrimitiveDataFrameColumnComputations.tt +++ b/src/Microsoft.Data.Analysis/PrimitiveDataFrameColumnComputations.tt @@ -55,6 +55,11 @@ namespace Microsoft.Data.Analysis return (IPrimitiveColumnComputation)new <#=type.ClassPrefix#>Computation(); } <# } #> + else if (typeof(T) == typeof(DateTime)) + { + return (IPrimitiveColumnComputation)new DateTimeComputation(); + } + throw new NotSupportedException(); } } diff --git a/test/Microsoft.Data.Analysis.Tests/DataFrame.IOTests.cs b/test/Microsoft.Data.Analysis.Tests/DataFrame.IOTests.cs index 93bf2dad54..b35d15b207 100644 --- a/test/Microsoft.Data.Analysis.Tests/DataFrame.IOTests.cs +++ b/test/Microsoft.Data.Analysis.Tests/DataFrame.IOTests.cs @@ -94,6 +94,10 @@ internal static void VerifyColumnTypes(DataFrame df, bool testArrowStringColumn Assert.IsType(column); } } + else if (dataType == typeof(DateTime)) + { + Assert.IsType>(column); + } else { throw new NotImplementedException("Unit test has to be updated"); @@ -384,6 +388,83 @@ void Verify(DataFrame df) Verify(df); } + [Fact] + public void TestReadCsvWithTypesDateTime() + { + string data = @"vendor_id,rate_code,passenger_count,trip_time_in_secs,trip_distance,payment_type,fare_amount,date +CMT,1,1,1271,3.8,CRD,17.5,1-june-2020 +CMT,1,1,474,1.5,CRD,8,2-june-2020 +CMT,1,1,637,1.4,CRD,8.5,3-june-2020 +,,,,,,, +CMT,1,1,181,0.6,CSH,4.5,4-june-2020"; + + void Verify(DataFrame df, bool verifyDataTypes) + { + Assert.Equal(5, df.Rows.Count); + Assert.Equal(8, df.Columns.Count); + + if (verifyDataTypes) + { + Assert.True(typeof(string) == df.Columns[0].DataType); + Assert.True(typeof(short) == df.Columns[1].DataType); + Assert.True(typeof(int) == df.Columns[2].DataType); + Assert.True(typeof(long) == df.Columns[3].DataType); + Assert.True(typeof(float) == df.Columns[4].DataType); + Assert.True(typeof(string) == df.Columns[5].DataType); + Assert.True(typeof(double) == df.Columns[6].DataType); + Assert.True(typeof(DateTime) == df.Columns[7].DataType); + } + + Assert.Equal("vendor_id", df.Columns[0].Name); + Assert.Equal("rate_code", df.Columns[1].Name); + Assert.Equal("passenger_count", df.Columns[2].Name); + Assert.Equal("trip_time_in_secs", df.Columns[3].Name); + Assert.Equal("trip_distance", df.Columns[4].Name); + Assert.Equal("payment_type", df.Columns[5].Name); + Assert.Equal("fare_amount", df.Columns[6].Name); + Assert.Equal("date", df.Columns[7].Name); + VerifyColumnTypes(df); + + foreach (var column in df.Columns) + { + if (column.DataType != typeof(string)) + { + Assert.Equal(1, column.NullCount); + } + else + { + Assert.Equal(0, column.NullCount); + } + } + var nullRow = df.Rows[3]; + Assert.Equal("", nullRow[0]); + Assert.Null(nullRow[1]); + Assert.Null(nullRow[2]); + Assert.Null(nullRow[3]); + Assert.Null(nullRow[4]); + Assert.Equal("", nullRow[5]); + Assert.Null(nullRow[6]); + Assert.Null(nullRow[7]); + + var dateTimeColumn = df.Columns["date"]; + Assert.Equal(new DateTime(2020, 06, 01), dateTimeColumn[0]); + Assert.Equal(new DateTime(2020, 06, 02), dateTimeColumn[1]); + Assert.Equal(new DateTime(2020, 06, 03), dateTimeColumn[2]); + Assert.Null(dateTimeColumn[3]); + Assert.Equal(new DateTime(2020, 06, 04), dateTimeColumn[4]); + } + + DataFrame df = DataFrame.LoadCsv(GetStream(data), dataTypes: new Type[] { typeof(string), typeof(short), typeof(int), typeof(long), typeof(float), typeof(string), typeof(double), typeof(DateTime) }); + Verify(df, true); + df = DataFrame.LoadCsvFromString(data, dataTypes: new Type[] { typeof(string), typeof(short), typeof(int), typeof(long), typeof(float), typeof(string), typeof(double), typeof(DateTime) }); + Verify(df, true); + // Verify without dataTypes + df = DataFrame.LoadCsv(GetStream(data)); + Verify(df, false); + df = DataFrame.LoadCsvFromString(data); + Verify(df, false); + } + [Fact] public void TestReadCsvWithPipeSeparator() { diff --git a/test/Microsoft.Data.Analysis.Tests/DataFrameTests.cs b/test/Microsoft.Data.Analysis.Tests/DataFrameTests.cs index 34b676062a..72e9e628da 100644 --- a/test/Microsoft.Data.Analysis.Tests/DataFrameTests.cs +++ b/test/Microsoft.Data.Analysis.Tests/DataFrameTests.cs @@ -125,6 +125,20 @@ public static DataFrame MakeDataFrameWithNumericAndStringColumns(int length, boo return df; } + internal static DateTime SampleDateTime = new DateTime(2021, 06, 04); + public static DataFrame MakeDataFrameWithNumericStringAndDateTimeColumns(int length, bool withNulls = true) + { + DataFrame df = MakeDataFrameWithNumericAndStringColumns(length, withNulls); + + DataFrameColumn dateTimeColumn = new PrimitiveDataFrameColumn("DateTime", Enumerable.Range(0, length).Select(x => SampleDateTime.AddDays(x))); + df.Columns.Insert(df.Columns.Count, dateTimeColumn); + if (withNulls) + { + dateTimeColumn[length / 2] = null; + } + return df; + } + public static DataFrame MakeDataFrameWithNumericColumns(int length, bool withNulls = true) { DataFrameColumn byteColumn = new ByteDataFrameColumn("Byte", Enumerable.Range(0, length).Select(x => (byte)x)); @@ -798,6 +812,169 @@ public void TestComputations() } } + [Fact] + public void TestComputationsIncludingDateTime() + { + DataFrame df = MakeDataFrameWithNumericStringAndDateTimeColumns(10); + df["Int"][0] = -10; + Assert.Equal(-10, df.Columns["Int"][0]); + + DataFrameColumn absColumn = df.Columns["Int"].Abs(); + Assert.Equal(10, absColumn[0]); + Assert.Equal(-10, df.Columns["Int"][0]); + df.Columns["Int"].Abs(true); + Assert.Equal(10, df.Columns["Int"][0]); + + Assert.Throws(() => df.Columns["Byte"].All()); + Assert.Throws(() => df.Columns["Byte"].Any()); + Assert.Throws(() => df.Columns["Char"].All()); + Assert.Throws(() => df.Columns["Char"].Any()); + Assert.Throws(() => df.Columns["Decimal"].All()); + Assert.Throws(() => df.Columns["Decimal"].Any()); + Assert.Throws(() => df.Columns["Double"].All()); + Assert.Throws(() => df.Columns["Double"].Any()); + Assert.Throws(() => df.Columns["Float"].All()); + Assert.Throws(() => df.Columns["Float"].Any()); + Assert.Throws(() => df.Columns["Int"].All()); + Assert.Throws(() => df.Columns["Int"].Any()); + Assert.Throws(() => df.Columns["Long"].All()); + Assert.Throws(() => df.Columns["Long"].Any()); + Assert.Throws(() => df.Columns["Sbyte"].All()); + Assert.Throws(() => df.Columns["Sbyte"].Any()); + Assert.Throws(() => df.Columns["Short"].All()); + Assert.Throws(() => df.Columns["Short"].Any()); + Assert.Throws(() => df.Columns["Uint"].All()); + Assert.Throws(() => df.Columns["Uint"].Any()); + Assert.Throws(() => df.Columns["Ulong"].All()); + Assert.Throws(() => df.Columns["Ulong"].Any()); + Assert.Throws(() => df.Columns["Ushort"].All()); + Assert.Throws(() => df.Columns["Ushort"].Any()); + Assert.Throws(() => df.Columns["DateTime"].All()); + Assert.Throws(() => df.Columns["DateTime"].Any()); + + // Test the computation results + var maxDate = SampleDateTime.AddDays(100); + df.Columns["DateTime"][0] = maxDate; + DataFrameColumn dateTimeColumn = df.Columns["DateTime"].CumulativeMax(); + for (int i = 0; i < dateTimeColumn.Length; i++) + { + if (i == 5) + Assert.Null(dateTimeColumn[i]); + else + Assert.Equal(maxDate, (DateTime)dateTimeColumn[i]); + } + Assert.Equal(maxDate, dateTimeColumn.Max()); + + df.Columns["Double"][0] = 100.0; + DataFrameColumn doubleColumn = df.Columns["Double"].CumulativeMax(); + for (int i = 0; i < doubleColumn.Length; i++) + { + if (i == 5) + Assert.Null(doubleColumn[i]); + else + Assert.Equal(100.0, (double)doubleColumn[i]); + } + Assert.Equal(1.0, df.Columns["Double"][1]); + df.Columns["Double"].CumulativeMax(true); + for (int i = 0; i < df.Columns["Double"].Length; i++) + { + if (i == 5) + Assert.Null(df.Columns["Double"][i]); + else + Assert.Equal(100.0, (double)df.Columns["Double"][i]); + } + + df.Columns["Float"][0] = -10.0f; + DataFrameColumn floatColumn = df.Columns["Float"].CumulativeMin(); + for (int i = 0; i < floatColumn.Length; i++) + { + if (i == 5) + Assert.Null(floatColumn[i]); + else + Assert.Equal(-10.0f, (float)floatColumn[i]); + } + Assert.Equal(9.0f, df.Columns["Float"][9]); + df.Columns["Float"].CumulativeMin(true); + for (int i = 0; i < df.Columns["Float"].Length; i++) + { + if (i == 5) + Assert.Null(df.Columns["Float"][i]); + else + Assert.Equal(-10.0f, (float)df.Columns["Float"][i]); + } + + DataFrameColumn uintColumn = df.Columns["Uint"].CumulativeProduct(); + Assert.Equal((uint)0, uintColumn[8]); + Assert.Equal((uint)8, df.Columns["Uint"][8]); + df.Columns["Uint"].CumulativeProduct(true); + Assert.Equal((uint)0, df.Columns["Uint"][9]); + + DataFrameColumn ushortColumn = df.Columns["Ushort"].CumulativeSum(); + Assert.Equal((ushort)40, ushortColumn[9]); + Assert.Equal((ushort)9, df.Columns["Ushort"][9]); + df.Columns["Ushort"].CumulativeSum(true); + Assert.Equal((ushort)40, df.Columns["Ushort"][9]); + + Assert.Equal(100.0, df.Columns["Double"].Max()); + Assert.Equal(-10.0f, df.Columns["Float"].Min()); + Assert.Equal((uint)0, df.Columns["Uint"].Product()); + Assert.Equal((ushort)140, df.Columns["Ushort"].Sum()); + + df.Columns["Double"][0] = 100.1; + Assert.Equal(100.1, df.Columns["Double"][0]); + DataFrameColumn roundColumn = df.Columns["Double"].Round(); + Assert.Equal(100.0, roundColumn[0]); + Assert.Equal(100.1, df.Columns["Double"][0]); + df.Columns["Double"].Round(true); + Assert.Equal(100.0, df.Columns["Double"][0]); + + // Test that none of the numeric column types throw + for (int i = 0; i < df.Columns.Count; i++) + { + DataFrameColumn column = df.Columns[i]; + if (column.DataType == typeof(bool)) + { + Assert.Throws(() => column.CumulativeMax()); + Assert.Throws(() => column.CumulativeMin()); + Assert.Throws(() => column.CumulativeProduct()); + Assert.Throws(() => column.CumulativeSum()); + Assert.Throws(() => column.Max()); + Assert.Throws(() => column.Min()); + Assert.Throws(() => column.Product()); + Assert.Throws(() => column.Sum()); + continue; + } + else if (column.DataType == typeof(string)) + { + Assert.Throws(() => column.CumulativeMax()); + Assert.Throws(() => column.CumulativeMin()); + Assert.Throws(() => column.CumulativeProduct()); + Assert.Throws(() => column.CumulativeSum()); + Assert.Throws(() => column.Max()); + Assert.Throws(() => column.Min()); + Assert.Throws(() => column.Product()); + Assert.Throws(() => column.Sum()); + continue; + } + else if (column.DataType == typeof(DateTime)) + { + Assert.Throws(() => column.CumulativeProduct()); + Assert.Throws(() => column.CumulativeSum()); + Assert.Throws(() => column.Product()); + Assert.Throws(() => column.Sum()); + continue; + } + column.CumulativeMax(); + column.CumulativeMin(); + column.CumulativeProduct(); + column.CumulativeSum(); + column.Max(); + column.Min(); + column.Product(); + column.Sum(); + } + } + [Fact] public void TestOrderBy() {