resgroup/customer-tests-excel

View on GitHub
CustomerTestsExcel/ExcelToCode/ExcelState.cs

Summary

Maintainability
A
3 hrs
Test Coverage
using System;

namespace CustomerTestsExcel.ExcelToCode
{
    public class ExcelState
    {
        public ITabularPage Worksheet { get; private set; }
        public uint Row { get; private set; }
        public uint Column { get; private set; }

        public ExcelState() { }

        internal void Initialise(ITabularPage worksheet)
        {
            Worksheet = worksheet;
            Row = 1;
            Column = 1;
        }

        public bool RowToColumnIsEmpty(uint column)
        {
            for (uint columnToCheck = 1; columnToCheck <= column; columnToCheck++)
            {
                if (!string.IsNullOrWhiteSpace(Cell(Row, columnToCheck))) return false;
            }

            return true;
        }

        public bool RowToCurrentColumnIsEmpty() =>
            RowToColumnIsEmpty(Column);

        public bool AllColumnsAreEmpty() =>
            RowToColumnIsEmpty(GetLastColumn());

        public bool AnyPrecedingColumnHasAValue() =>
            !RowToColumnIsEmpty(Column - 1);

        public bool AnyFollowingColumnHasAValue(int rowOffset = 0)
        {
            for (uint columnToCheck = Column + 1; columnToCheck <
                GetLastColumn(); columnToCheck++)
            {
                if (!string.IsNullOrWhiteSpace(Cell((uint)(Row + rowOffset), columnToCheck))) return true;
            }

            return false;
        }

        public void MoveUp(uint by = 1) =>
            Row -= by;

        public void MoveDown(uint by = 1) =>
            Row += by;

        public void MoveDownToToken(string token)
        {
            while (CurrentCell() != token)
            {
                if (Row > GetLastRow()) throw new ExcelToCodeException(string.Format("Cannot find token {0} in column {1}, reached last row ({2})", token, Column, Row));
                MoveDown();
            }
        }

        public void MoveRight(uint by = 1) =>
            Column += by;

        public void MoveLeft(uint by = 1) =>
            Column -= by;

        public uint? FindTokenInCurrentRowFromCurrentColumn(string token)
        {
            uint columnToCheck = Column;
            while (Cell(Row, columnToCheck) != token)
            {
                if (columnToCheck > GetLastColumn()) return null;
                columnToCheck++;
            }

            return columnToCheck;
        }

        public TidyUp SavePosition()
        {
            uint savedRow = this.Row;
            uint savedColumn = Column;

            return new TidyUp(() => { Row = savedRow; Column = savedColumn; });
        }

        public TidyUp AutoRestoreMoveDown(uint by = 1)
        {
            MoveDown(by);
            return new TidyUp(() => MoveUp(by));
        }

        public TidyUp AutoRestoreMoveRight(uint by = 1)
        {
            MoveRight(by);
            return new TidyUp(() => MoveLeft(by));
        }

        public TidyUp AutoRestoreMoveDownRight(uint downBy = 1, uint rightBy = 1)
        {
            MoveRight(rightBy);
            MoveDown(downBy);

            return new TidyUp(() =>
            {
                MoveLeft(rightBy);
                MoveUp(downBy);
            });
        }

        public uint GetLastRow() =>
            Worksheet.MaxRow;

        public uint GetLastColumn() =>
            Worksheet.MaxColumn + 20; // maxcolumn seems to underreport the amount of columns that there are ...

        public string PeekAbove(uint by = 1) =>
            Cell(Row - by, Column);

        public string PeekBelow(uint by = 1) =>
            Cell(Row + by, Column);

        public string PeekRight(uint by = 1) =>
            Cell(Row, Column + by);

        public string PeekBelowRight(uint belowBy = 1, uint rightBy = 1) =>
            Cell(Row + belowBy, Column + rightBy);

        public string CurrentCell() =>
            Cell(Row, Column);

        public object CurrentCellRaw() =>
            CellRaw(Row, Column);

        public string Cell(uint row, uint column)
        {
            var value = Worksheet.GetCell(row, column).Value;

            return (value == null) ? "" : value.ToString();
        }

        public object CellRaw(uint row, uint column) =>
            Worksheet.GetCell(row, column).Value;

        public string CellReferenceA1Style() =>
            CellReferenceA1Style(Row, Column);

        public string CellReferenceA1Style(uint row, uint column) =>
            $"{ColumnReferenceA1Style(column)}{row}";

        public string ColumnReferenceA1Style()
            => ColumnReferenceA1Style(Column);

        public string ColumnReferenceA1Style(uint column)
        {
            const uint A = 65;
            const uint NUMBER_OF_LETTERS_IN_ALPHABET = 26;
            uint dividend = column;
            string columnName = String.Empty;
            uint modulo;

            // this works because the int representation of all capital letters starts at 65, is continuous and in alphabetical order
            while (dividend > 0)
            {
                modulo = (dividend - 1) % NUMBER_OF_LETTERS_IN_ALPHABET;
                columnName = Convert.ToChar(A + modulo).ToString() + columnName;
                dividend = (dividend - modulo) / NUMBER_OF_LETTERS_IN_ALPHABET;
            }

            return columnName;
        }
    }
}