Skip to content

Code refactoring + unit tests #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 85 additions & 80 deletions AsciiTableGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,92 +1,97 @@
using System.Collections.Generic;
using System.Data;
using System.Data;
using System.Globalization;
using System.Linq;
using System.Text;

namespace AsciiTableGenerators
{
public class AsciiTableGenerator
{
public static StringBuilder CreateAsciiTableFromDataTable(DataTable table)
{
var lenghtByColumnDictionary = GetTotalSpaceForEachColumn(table);
public static class AsciiTableGenerator
{
private const string COLUMN_SEPARATOR = " | ";
private const string ALIGN_CHAR = " ";
private const string HEADER_SEPARATOR = "-";
private const int SKIP_HEADER_SEPARATORS = 2;

public static StringBuilder CreateAsciiTableFromDataTable(DataTable table)
{
var tableBuilder = new StringBuilder();
var lengthByColumn = GetLengthByColumn(table);
AppendColumns(table, tableBuilder, lengthByColumn);
AppendRows(table, tableBuilder, lengthByColumn);

var tableBuilder = new StringBuilder();
AppendColumns(table, tableBuilder, lenghtByColumnDictionary);
AppendRows(table, lenghtByColumnDictionary, tableBuilder);
return tableBuilder;
}
return tableBuilder;
}

private static void AppendRows(DataTable table, IReadOnlyDictionary<int, int> lenghtByColumnDictionary,
StringBuilder tableBuilder)
{
for (var i = 0; i < table.Rows.Count; i++)
{
var rowBuilder = new StringBuilder();
for (var j = 0; j < table.Columns.Count; j++)
{
rowBuilder.Append(PadWithSpaceAndSeperator(table.Rows[i][j].ToString().Trim(),
lenghtByColumnDictionary[j]));
}
tableBuilder.AppendLine(rowBuilder.ToString());
}
}
private static Dictionary<int, int> GetLengthByColumn(DataTable table)
{
var lengthByColumn = new Dictionary<int, int>();

private static void AppendColumns(DataTable table, StringBuilder builder,
IReadOnlyDictionary<int, int> lenghtByColumnDictionary)
{
for (var i = 0; i < table.Columns.Count; i++)
{
var columName = table.Columns[i].ColumnName.Trim();
var paddedColumNames = PadWithSpaceAndSeperator(ToTitleCase(columName), lenghtByColumnDictionary[i]);
builder.Append(paddedColumNames);
}
builder.AppendLine();
builder.AppendLine(string.Join("", Enumerable.Repeat("-", builder.ToString().Length - 3).ToArray()));
}
for (var columnIndex = 0; columnIndex < table.Columns.Count; columnIndex++)
{
var rowsLengths = new int[table.Rows.Count];

private static string ToTitleCase(string columnName)
{
return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(columnName.Replace("_", " "));
}
for (var rowIndex = 0; rowIndex < table.Rows.Count; rowIndex++)
{
rowsLengths[rowIndex] = table.Rows[rowIndex][columnIndex].ToString()?.Trim().Length ?? 0;
}

private static Dictionary<int, int> GetTotalSpaceForEachColumn(DataTable table)
{
var lengthByColumn = new Dictionary<int, int>();
for (var i = 0; i < table.Columns.Count; i++)
{
var length = new int[table.Rows.Count];
for (var j = 0; j < table.Rows.Count; j++)
{
length[j] = table.Rows[j][i].ToString().Trim().Length;
}
lengthByColumn[i] = length.Max();
}
return CompareToColumnNameLengthAndUpdate(table, lengthByColumn);
}
if (rowsLengths.Length == 0)
{
lengthByColumn[columnIndex] = table.Columns[columnIndex].ColumnName.Trim().Length;
}
else
{
lengthByColumn[columnIndex] = Math.Max(rowsLengths.Max(), table.Columns[columnIndex].ColumnName.Trim().Length);
}
}

private static Dictionary<int, int> CompareToColumnNameLengthAndUpdate(DataTable table,
IReadOnlyDictionary<int, int> lenghtByColumnDictionary)
{
var dictionary = new Dictionary<int, int>();
for (var i = 0; i < table.Columns.Count; i++)
{
var columnNameLength = table.Columns[i].ColumnName.Trim().Length;
dictionary[i] = columnNameLength > lenghtByColumnDictionary[i]
? columnNameLength
: lenghtByColumnDictionary[i];
}
return dictionary;
}
return lengthByColumn;
}

private static string PadWithSpaceAndSeperator(string value, int totalColumnLength)
{
var remaningSpace = value.Length < totalColumnLength
? totalColumnLength - value.Length
: value.Length - totalColumnLength;
var spaces = string.Join("", Enumerable.Repeat(" ", remaningSpace).ToArray());
return value + spaces + " | ";
}
}
}
private static void AppendColumns(DataTable table, StringBuilder tableBuilder, IReadOnlyDictionary<int, int> lengthByColumn)
{
for (var columnIndex = 0; columnIndex < table.Columns.Count; columnIndex++)
{
var columName = table.Columns[columnIndex].ColumnName.Trim();
var paddedColumNames = AlignValueAndAddSeparator(ToTitleCase(columName), lengthByColumn[columnIndex]);
tableBuilder.Append(paddedColumNames);
}

tableBuilder.AppendLine();
// Skipping separators is needed because tableBuilder.Lenght contains also invisible characters like \n. 11.04.2022. Artem Yurchenko
tableBuilder.AppendLine(string.Join("", Enumerable.Repeat(HEADER_SEPARATOR, tableBuilder.Length - SKIP_HEADER_SEPARATORS).ToArray()));
}

private static string ToTitleCase(string columnName)
{
return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(columnName.Replace("_", " "));
}

private static void AppendRows(DataTable table, StringBuilder tableBuilder, IReadOnlyDictionary<int, int> lengthByColumn)
{
for (var rowIndex = 0; rowIndex < table.Rows.Count; rowIndex++)
{
var rowBuilder = new StringBuilder();

for (var columnIndex = 0; columnIndex < table.Columns.Count; columnIndex++)
{
rowBuilder.Append(AlignValueAndAddSeparator(table.Rows[rowIndex][columnIndex].ToString()?.Trim(), lengthByColumn[columnIndex]));
}

tableBuilder.AppendLine(rowBuilder.ToString());
}
}

private static string AlignValueAndAddSeparator(string? value, int columnLength)
{
var spaces = string.Empty;

if (value != null)
{
var remainingSpace = value.Length < columnLength ? columnLength - value.Length : value.Length - columnLength;
spaces = string.Join("", Enumerable.Repeat(ALIGN_CHAR, remainingSpace).ToArray());
}

return value + spaces + COLUMN_SEPARATOR;
}
}
}
45 changes: 45 additions & 0 deletions AsciiTableGeneratorTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System.Data;

namespace AsciiTableGenerators;

public class AsciiTableGeneratorTests
{
// NUnit was used. 11.04.2022. Artem Yurchenko

// [Test]
// public void CreateTableWithHeadersOnly_GeneratorReturnsExpectedString_True ()
// {
// DataTable table = new();
// table.Columns.Add("Column1");
// table.Columns.Add("Column2");
//
// string tableString = AsciiTableGenerator.CreateAsciiTableFromDataTable(table).ToString();
//
// Assert.AreEqual("Column1 | Column2 | \n-------------------\n", tableString);
// }
//
// [Test]
// public void CreateSimpleTable_GeneratorReturnsExpectedString_True ()
// {
// DataTable table = new();
// table.Columns.Add("Column1");
// table.Columns.Add("Column2");
// table.Rows.Add("Row1", "Row2");
//
// string tableString = AsciiTableGenerator.CreateAsciiTableFromDataTable(table).ToString();
//
// Assert.AreEqual("Column1 | Column2 | \n-------------------\nRow1 | Row2 | \n", tableString);
// }
//
// [Test]
// public void CreateTableWithRowBiggerThanColumn_GeneratorReturnsExpectedString_True ()
// {
// DataTable table = new();
// table.Columns.Add("Column1");
// table.Rows.Add("Column1Bigger");
//
// string tableString = AsciiTableGenerator.CreateAsciiTableFromDataTable(table).ToString();
//
// Assert.AreEqual("Column1 | \n---------------\nColumn1Bigger | \n", tableString);
// }
}