diff --git a/Terminal.Gui/ConsoleDrivers/MockDriver/MockConsole.cs b/Terminal.Gui/ConsoleDrivers/MockDriver/MockConsole.cs new file mode 100644 index 000000000..ffb3b0c32 --- /dev/null +++ b/Terminal.Gui/ConsoleDrivers/MockDriver/MockConsole.cs @@ -0,0 +1,1661 @@ +// +// MockConsole.cs: A mock .NET Windows Console API implementaiton for unit tests. +// +// Authors: +// Charlie Kindel (github.com/tig) +// +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Terminal.Gui { + /// + /// + /// + public static class MockConsole { + + // + // Summary: + // Gets or sets the width of the console window. + // + // Returns: + // The width of the console window measured in columns. + // + // Exceptions: + // T:System.ArgumentOutOfRangeException: + // The value of the System.Console.WindowWidth property or the value of the System.Console.WindowHeight + // property is less than or equal to 0.-or-The value of the System.Console.WindowHeight + // property plus the value of the System.Console.WindowTop property is greater than + // or equal to System.Int16.MaxValue.-or-The value of the System.Console.WindowWidth + // property or the value of the System.Console.WindowHeight property is greater + // than the largest possible window width or height for the current screen resolution + // and console font. + // + // T:System.IO.IOException: + // Error reading or writing information. + public static int WindowWidth { get; set; } = 80; + // + // Summary: + // Gets a value that indicates whether output has been redirected from the standard + // output stream. + // + // Returns: + // true if output is redirected; otherwise, false. + public static bool IsOutputRedirected { get; } + // + // Summary: + // Gets a value that indicates whether the error output stream has been redirected + // from the standard error stream. + // + // Returns: + // true if error output is redirected; otherwise, false. + public static bool IsErrorRedirected { get; } + // + // Summary: + // Gets the standard input stream. + // + // Returns: + // A System.IO.TextReader that represents the standard input stream. + public static TextReader In { get; } + // + // Summary: + // Gets the standard output stream. + // + // Returns: + // A System.IO.TextWriter that represents the standard output stream. + public static TextWriter Out { get; } + // + // Summary: + // Gets the standard error output stream. + // + // Returns: + // A System.IO.TextWriter that represents the standard error output stream. + public static TextWriter Error { get; } + // + // Summary: + // Gets or sets the encoding the console uses to read input. + // + // Returns: + // The encoding used to read console input. + // + // Exceptions: + // T:System.ArgumentNullException: + // The property value in a set operation is null. + // + // T:System.IO.IOException: + // An error occurred during the execution of this operation. + // + // T:System.Security.SecurityException: + // Your application does not have permission to perform this operation. + public static Encoding InputEncoding { get; set; } + // + // Summary: + // Gets or sets the encoding the console uses to write output. + // + // Returns: + // The encoding used to write console output. + // + // Exceptions: + // T:System.ArgumentNullException: + // The property value in a set operation is null. + // + // T:System.IO.IOException: + // An error occurred during the execution of this operation. + // + // T:System.Security.SecurityException: + // Your application does not have permission to perform this operation. + public static Encoding OutputEncoding { get; set; } + // + // Summary: + // Gets or sets the background color of the console. + // + // Returns: + // A value that specifies the background color of the console; that is, the color + // that appears behind each character. The default is black. + // + // Exceptions: + // T:System.ArgumentException: + // The color specified in a set operation is not a valid member of System.ConsoleColor. + // + // T:System.Security.SecurityException: + // The user does not have permission to perform this action. + // + // T:System.IO.IOException: + // An I/O error occurred. + /// + /// + /// + public static ConsoleColor BackgroundColor { get; set; } = _defaultBackgroundColor; + static ConsoleColor _defaultBackgroundColor = ConsoleColor.Black; + + // + // Summary: + // Gets or sets the foreground color of the console. + // + // Returns: + // A System.ConsoleColor that specifies the foreground color of the console; that + // is, the color of each character that is displayed. The default is gray. + // + // Exceptions: + // T:System.ArgumentException: + // The color specified in a set operation is not a valid member of System.ConsoleColor. + // + // T:System.Security.SecurityException: + // The user does not have permission to perform this action. + // + // T:System.IO.IOException: + // An I/O error occurred. + /// + /// + /// + public static ConsoleColor ForegroundColor { get; set; } = _defaultForegroundColor; + static ConsoleColor _defaultForegroundColor = ConsoleColor.Gray; + // + // Summary: + // Gets or sets the height of the buffer area. + // + // Returns: + // The current height, in rows, of the buffer area. + // + // Exceptions: + // T:System.ArgumentOutOfRangeException: + // The value in a set operation is less than or equal to zero.-or- The value in + // a set operation is greater than or equal to System.Int16.MaxValue.-or- The value + // in a set operation is less than System.Console.WindowTop + System.Console.WindowHeight. + // + // T:System.Security.SecurityException: + // The user does not have permission to perform this action. + // + // T:System.IO.IOException: + // An I/O error occurred. + public static int BufferHeight { get; set; } = 25; + // + // Summary: + // Gets or sets the width of the buffer area. + // + // Returns: + // The current width, in columns, of the buffer area. + // + // Exceptions: + // T:System.ArgumentOutOfRangeException: + // The value in a set operation is less than or equal to zero.-or- The value in + // a set operation is greater than or equal to System.Int16.MaxValue.-or- The value + // in a set operation is less than System.Console.WindowLeft + System.Console.WindowWidth. + // + // T:System.Security.SecurityException: + // The user does not have permission to perform this action. + // + // T:System.IO.IOException: + // An I/O error occurred. + public static int BufferWidth { get; set; } = 80; + // + // Summary: + // Gets or sets the height of the console window area. + // + // Returns: + // The height of the console window measured in rows. + // + // Exceptions: + // T:System.ArgumentOutOfRangeException: + // The value of the System.Console.WindowWidth property or the value of the System.Console.WindowHeight + // property is less than or equal to 0.-or-The value of the System.Console.WindowHeight + // property plus the value of the System.Console.WindowTop property is greater than + // or equal to System.Int16.MaxValue.-or-The value of the System.Console.WindowWidth + // property or the value of the System.Console.WindowHeight property is greater + // than the largest possible window width or height for the current screen resolution + // and console font. + // + // T:System.IO.IOException: + // Error reading or writing information. + public static int WindowHeight { get; set; } = 25; + // + // Summary: + // Gets or sets a value indicating whether the combination of the System.ConsoleModifiers.Control + // modifier key and System.ConsoleKey.C console key (Ctrl+C) is treated as ordinary + // input or as an interruption that is handled by the operating system. + // + // Returns: + // true if Ctrl+C is treated as ordinary input; otherwise, false. + // + // Exceptions: + // T:System.IO.IOException: + // Unable to get or set the input mode of the console input buffer. + public static bool TreatControlCAsInput { get; set; } + // + // Summary: + // Gets the largest possible number of console window columns, based on the current + // font and screen resolution. + // + // Returns: + // The width of the largest possible console window measured in columns. + public static int LargestWindowWidth { get; } + // + // Summary: + // Gets the largest possible number of console window rows, based on the current + // font and screen resolution. + // + // Returns: + // The height of the largest possible console window measured in rows. + public static int LargestWindowHeight { get; } + // + // Summary: + // Gets or sets the leftmost position of the console window area relative to the + // screen buffer. + // + // Returns: + // The leftmost console window position measured in columns. + // + // Exceptions: + // T:System.ArgumentOutOfRangeException: + // In a set operation, the value to be assigned is less than zero.-or-As a result + // of the assignment, System.Console.WindowLeft plus System.Console.WindowWidth + // would exceed System.Console.BufferWidth. + // + // T:System.IO.IOException: + // Error reading or writing information. + public static int WindowLeft { get; set; } + // + // Summary: + // Gets or sets the top position of the console window area relative to the screen + // buffer. + // + // Returns: + // The uppermost console window position measured in rows. + // + // Exceptions: + // T:System.ArgumentOutOfRangeException: + // In a set operation, the value to be assigned is less than zero.-or-As a result + // of the assignment, System.Console.WindowTop plus System.Console.WindowHeight + // would exceed System.Console.BufferHeight. + // + // T:System.IO.IOException: + // Error reading or writing information. + public static int WindowTop { get; set; } + // + // Summary: + // Gets or sets the column position of the cursor within the buffer area. + // + // Returns: + // The current position, in columns, of the cursor. + // + // Exceptions: + // T:System.ArgumentOutOfRangeException: + // The value in a set operation is less than zero.-or- The value in a set operation + // is greater than or equal to System.Console.BufferWidth. + // + // T:System.Security.SecurityException: + // The user does not have permission to perform this action. + // + // T:System.IO.IOException: + // An I/O error occurred. + public static int CursorLeft { get; set; } + // + // Summary: + // Gets or sets the row position of the cursor within the buffer area. + // + // Returns: + // The current position, in rows, of the cursor. + // + // Exceptions: + // T:System.ArgumentOutOfRangeException: + // The value in a set operation is less than zero.-or- The value in a set operation + // is greater than or equal to System.Console.BufferHeight. + // + // T:System.Security.SecurityException: + // The user does not have permission to perform this action. + // + // T:System.IO.IOException: + // An I/O error occurred. + public static int CursorTop { get; set; } + // + // Summary: + // Gets or sets the height of the cursor within a character cell. + // + // Returns: + // The size of the cursor expressed as a percentage of the height of a character + // cell. The property value ranges from 1 to 100. + // + // Exceptions: + // T:System.ArgumentOutOfRangeException: + // The value specified in a set operation is less than 1 or greater than 100. + // + // T:System.Security.SecurityException: + // The user does not have permission to perform this action. + // + // T:System.IO.IOException: + // An I/O error occurred. + public static int CursorSize { get; set; } + // + // Summary: + // Gets or sets a value indicating whether the cursor is visible. + // + // Returns: + // true if the cursor is visible; otherwise, false. + // + // Exceptions: + // T:System.Security.SecurityException: + // The user does not have permission to perform this action. + // + // T:System.IO.IOException: + // An I/O error occurred. + public static bool CursorVisible { get; set; } + // + // Summary: + // Gets or sets the title to display in the console title bar. + // + // Returns: + // The string to be displayed in the title bar of the console. The maximum length + // of the title string is 24500 characters. + // + // Exceptions: + // T:System.InvalidOperationException: + // In a get operation, the retrieved title is longer than 24500 characters. + // + // T:System.ArgumentOutOfRangeException: + // In a set operation, the specified title is longer than 24500 characters. + // + // T:System.ArgumentNullException: + // In a set operation, the specified title is null. + // + // T:System.IO.IOException: + // An I/O error occurred. + public static string Title { get; set; } + // + // Summary: + // Gets a value indicating whether a key press is available in the input stream. + // + // Returns: + // true if a key press is available; otherwise, false. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + // + // T:System.InvalidOperationException: + // Standard input is redirected to a file instead of the keyboard. + public static bool KeyAvailable { get; } + // + // Summary: + // Gets a value indicating whether the NUM LOCK keyboard toggle is turned on or + // turned off. + // + // Returns: + // true if NUM LOCK is turned on; false if NUM LOCK is turned off. + public static bool NumberLock { get; } + // + // Summary: + // Gets a value indicating whether the CAPS LOCK keyboard toggle is turned on or + // turned off. + // + // Returns: + // true if CAPS LOCK is turned on; false if CAPS LOCK is turned off. + public static bool CapsLock { get; } + // + // Summary: + // Gets a value that indicates whether input has been redirected from the standard + // input stream. + // + // Returns: + // true if input is redirected; otherwise, false. + public static bool IsInputRedirected { get; } + + // + // Summary: + // Occurs when the System.ConsoleModifiers.Control modifier key (Ctrl) and either + // the System.ConsoleKey.C console key (C) or the Break key are pressed simultaneously + // (Ctrl+C or Ctrl+Break). + //public static event ConsoleCancelEventHandler CancelKeyPress; + + // + // Summary: + // Plays the sound of a beep through the console speaker. + // + // Exceptions: + // T:System.Security.HostProtectionException: + // This method was executed on a server, such as SQL Server, that does not permit + // access to a user interface. + public static void Beep () + { + throw new NotImplementedException (); + } + // + // Summary: + // Plays the sound of a beep of a specified frequency and duration through the console + // speaker. + // + // Parameters: + // frequency: + // The frequency of the beep, ranging from 37 to 32767 hertz. + // + // duration: + // The duration of the beep measured in milliseconds. + // + // Exceptions: + // T:System.ArgumentOutOfRangeException: + // frequency is less than 37 or more than 32767 hertz.-or- duration is less than + // or equal to zero. + // + // T:System.Security.HostProtectionException: + // This method was executed on a server, such as SQL Server, that does not permit + // access to the console. + public static void Beep (int frequency, int duration) + { + throw new NotImplementedException (); + } + // + // Summary: + // Clears the console buffer and corresponding console window of display information. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + public static void Clear () + { + _buffer = new char [WindowWidth, WindowHeight]; + SetCursorPosition (0, 0); + } + + static char [,] _buffer = new char [WindowWidth, WindowHeight]; + + // + // Summary: + // Copies a specified source area of the screen buffer to a specified destination + // area. + // + // Parameters: + // sourceLeft: + // The leftmost column of the source area. + // + // sourceTop: + // The topmost row of the source area. + // + // sourceWidth: + // The number of columns in the source area. + // + // sourceHeight: + // The number of rows in the source area. + // + // targetLeft: + // The leftmost column of the destination area. + // + // targetTop: + // The topmost row of the destination area. + // + // Exceptions: + // T:System.ArgumentOutOfRangeException: + // One or more of the parameters is less than zero.-or- sourceLeft or targetLeft + // is greater than or equal to System.Console.BufferWidth.-or- sourceTop or targetTop + // is greater than or equal to System.Console.BufferHeight.-or- sourceTop + sourceHeight + // is greater than or equal to System.Console.BufferHeight.-or- sourceLeft + sourceWidth + // is greater than or equal to System.Console.BufferWidth. + // + // T:System.Security.SecurityException: + // The user does not have permission to perform this action. + // + // T:System.IO.IOException: + // An I/O error occurred. + public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight, int targetLeft, int targetTop) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Copies a specified source area of the screen buffer to a specified destination + // area. + // + // Parameters: + // sourceLeft: + // The leftmost column of the source area. + // + // sourceTop: + // The topmost row of the source area. + // + // sourceWidth: + // The number of columns in the source area. + // + // sourceHeight: + // The number of rows in the source area. + // + // targetLeft: + // The leftmost column of the destination area. + // + // targetTop: + // The topmost row of the destination area. + // + // sourceChar: + // The character used to fill the source area. + // + // sourceForeColor: + // The foreground color used to fill the source area. + // + // sourceBackColor: + // The background color used to fill the source area. + // + // Exceptions: + // T:System.ArgumentOutOfRangeException: + // One or more of the parameters is less than zero.-or- sourceLeft or targetLeft + // is greater than or equal to System.Console.BufferWidth.-or- sourceTop or targetTop + // is greater than or equal to System.Console.BufferHeight.-or- sourceTop + sourceHeight + // is greater than or equal to System.Console.BufferHeight.-or- sourceLeft + sourceWidth + // is greater than or equal to System.Console.BufferWidth. + // + // T:System.ArgumentException: + // One or both of the color parameters is not a member of the System.ConsoleColor + // enumeration. + // + // T:System.Security.SecurityException: + // The user does not have permission to perform this action. + // + // T:System.IO.IOException: + // An I/O error occurred. + //[SecuritySafeCritical] + public static void MoveBufferArea (int sourceLeft, int sourceTop, int sourceWidth, int sourceHeight, int targetLeft, int targetTop, char sourceChar, ConsoleColor sourceForeColor, ConsoleColor sourceBackColor) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Acquires the standard error stream. + // + // Returns: + // The standard error stream. + public static Stream OpenStandardError () + { + throw new NotImplementedException (); + } + + // + // Summary: + // Acquires the standard error stream, which is set to a specified buffer size. + // + // Parameters: + // bufferSize: + // The internal stream buffer size. + // + // Returns: + // The standard error stream. + // + // Exceptions: + // T:System.ArgumentOutOfRangeException: + // bufferSize is less than or equal to zero. + public static Stream OpenStandardError (int bufferSize) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Acquires the standard input stream, which is set to a specified buffer size. + // + // Parameters: + // bufferSize: + // The internal stream buffer size. + // + // Returns: + // The standard input stream. + // + // Exceptions: + // T:System.ArgumentOutOfRangeException: + // bufferSize is less than or equal to zero. + public static Stream OpenStandardInput (int bufferSize) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Acquires the standard input stream. + // + // Returns: + // The standard input stream. + public static Stream OpenStandardInput () + { + throw new NotImplementedException (); + } + + // + // Summary: + // Acquires the standard output stream, which is set to a specified buffer size. + // + // Parameters: + // bufferSize: + // The internal stream buffer size. + // + // Returns: + // The standard output stream. + // + // Exceptions: + // T:System.ArgumentOutOfRangeException: + // bufferSize is less than or equal to zero. + public static Stream OpenStandardOutput (int bufferSize) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Acquires the standard output stream. + // + // Returns: + // The standard output stream. + public static Stream OpenStandardOutput () + { + throw new NotImplementedException (); + } + + // + // Summary: + // Reads the next character from the standard input stream. + // + // Returns: + // The next character from the input stream, or negative one (-1) if there are currently + // no more characters to be read. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + public static int Read () + { + throw new NotImplementedException (); + } + + // + // Summary: + // Obtains the next character or function key pressed by the user. The pressed key + // is optionally displayed in the console window. + // + // Parameters: + // intercept: + // Determines whether to display the pressed key in the console window. true to + // not display the pressed key; otherwise, false. + // + // Returns: + // An object that describes the System.ConsoleKey constant and Unicode character, + // if any, that correspond to the pressed console key. The System.ConsoleKeyInfo + // object also describes, in a bitwise combination of System.ConsoleModifiers values, + // whether one or more Shift, Alt, or Ctrl modifier keys was pressed simultaneously + // with the console key. + // + // Exceptions: + // T:System.InvalidOperationException: + // The System.Console.In property is redirected from some stream other than the + // console. + //[SecuritySafeCritical] + public static ConsoleKeyInfo ReadKey (bool intercept) + { + if (MockKeyPresses.Count > 0) { + return MockKeyPresses.Pop(); + } else { + return new ConsoleKeyInfo ('~', ConsoleKey.Oem3, false,false,false); + } + } + + public static Stack MockKeyPresses = new Stack (); + + // + // Summary: + // Obtains the next character or function key pressed by the user. The pressed key + // is displayed in the console window. + // + // Returns: + // An object that describes the System.ConsoleKey constant and Unicode character, + // if any, that correspond to the pressed console key. The System.ConsoleKeyInfo + // object also describes, in a bitwise combination of System.ConsoleModifiers values, + // whether one or more Shift, Alt, or Ctrl modifier keys was pressed simultaneously + // with the console key. + // + // Exceptions: + // T:System.InvalidOperationException: + // The System.Console.In property is redirected from some stream other than the + // console. + public static ConsoleKeyInfo ReadKey () + { + throw new NotImplementedException (); + } + + // + // Summary: + // Reads the next line of characters from the standard input stream. + // + // Returns: + // The next line of characters from the input stream, or null if no more lines are + // available. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + // + // T:System.OutOfMemoryException: + // There is insufficient memory to allocate a buffer for the returned string. + // + // T:System.ArgumentOutOfRangeException: + // The number of characters in the next line of characters is greater than System.Int32.MaxValue. + public static string ReadLine () + { + throw new NotImplementedException (); + } + + // + // Summary: + // Sets the foreground and background console colors to their defaults. + // + // Exceptions: + // T:System.Security.SecurityException: + // The user does not have permission to perform this action. + // + // T:System.IO.IOException: + // An I/O error occurred. + //[SecuritySafeCritical] + public static void ResetColor () + { + BackgroundColor = _defaultBackgroundColor; + ForegroundColor = _defaultForegroundColor; + } + + // + // Summary: + // Sets the height and width of the screen buffer area to the specified values. + // + // Parameters: + // width: + // The width of the buffer area measured in columns. + // + // height: + // The height of the buffer area measured in rows. + // + // Exceptions: + // T:System.ArgumentOutOfRangeException: + // height or width is less than or equal to zero.-or- height or width is greater + // than or equal to System.Int16.MaxValue.-or- width is less than System.Console.WindowLeft + // + System.Console.WindowWidth.-or- height is less than System.Console.WindowTop + // + System.Console.WindowHeight. + // + // T:System.Security.SecurityException: + // The user does not have permission to perform this action. + // + // T:System.IO.IOException: + // An I/O error occurred. + //[SecuritySafeCritical] + public static void SetBufferSize (int width, int height) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Sets the position of the cursor. + // + // Parameters: + // left: + // The column position of the cursor. Columns are numbered from left to right starting + // at 0. + // + // top: + // The row position of the cursor. Rows are numbered from top to bottom starting + // at 0. + // + // Exceptions: + // T:System.ArgumentOutOfRangeException: + // left or top is less than zero.-or- left is greater than or equal to System.Console.BufferWidth.-or- + // top is greater than or equal to System.Console.BufferHeight. + // + // T:System.Security.SecurityException: + // The user does not have permission to perform this action. + // + // T:System.IO.IOException: + // An I/O error occurred. + //[SecuritySafeCritical] + public static void SetCursorPosition (int left, int top) + { + CursorLeft = left; + CursorTop = top; + } + + // + // Summary: + // Sets the System.Console.Error property to the specified System.IO.TextWriter + // object. + // + // Parameters: + // newError: + // A stream that is the new standard error output. + // + // Exceptions: + // T:System.ArgumentNullException: + // newError is null. + // + // T:System.Security.SecurityException: + // The caller does not have the required permission. + //[SecuritySafeCritical] + public static void SetError (TextWriter newError) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Sets the System.Console.In property to the specified System.IO.TextReader object. + // + // Parameters: + // newIn: + // A stream that is the new standard input. + // + // Exceptions: + // T:System.ArgumentNullException: + // newIn is null. + // + // T:System.Security.SecurityException: + // The caller does not have the required permission. + //[SecuritySafeCritical] + public static void SetIn (TextReader newIn) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Sets the System.Console.Out property to the specified System.IO.TextWriter object. + // + // Parameters: + // newOut: + // A stream that is the new standard output. + // + // Exceptions: + // T:System.ArgumentNullException: + // newOut is null. + // + // T:System.Security.SecurityException: + // The caller does not have the required permission. + //[SecuritySafeCritical] + public static void SetOut (TextWriter newOut) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Sets the position of the console window relative to the screen buffer. + // + // Parameters: + // left: + // The column position of the upper left corner of the console window. + // + // top: + // The row position of the upper left corner of the console window. + // + // Exceptions: + // T:System.ArgumentOutOfRangeException: + // left or top is less than zero.-or- left + System.Console.WindowWidth is greater + // than System.Console.BufferWidth.-or- top + System.Console.WindowHeight is greater + // than System.Console.BufferHeight. + // + // T:System.Security.SecurityException: + // The user does not have permission to perform this action. + // + // T:System.IO.IOException: + // An I/O error occurred. + //[SecuritySafeCritical] + public static void SetWindowPosition (int left, int top) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Sets the height and width of the console window to the specified values. + // + // Parameters: + // width: + // The width of the console window measured in columns. + // + // height: + // The height of the console window measured in rows. + // + // Exceptions: + // T:System.ArgumentOutOfRangeException: + // width or height is less than or equal to zero.-or- width plus System.Console.WindowLeft + // or height plus System.Console.WindowTop is greater than or equal to System.Int16.MaxValue. + // -or- width or height is greater than the largest possible window width or height + // for the current screen resolution and console font. + // + // T:System.Security.SecurityException: + // The user does not have permission to perform this action. + // + // T:System.IO.IOException: + // An I/O error occurred. + //[SecuritySafeCritical] + public static void SetWindowSize (int width, int height) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the specified string value to the standard output stream. + // + // Parameters: + // value: + // The value to write. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + public static void Write (string value) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified object to the standard output + // stream. + // + // Parameters: + // value: + // The value to write, or null. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + public static void Write (object value) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified 64-bit unsigned integer value + // to the standard output stream. + // + // Parameters: + // value: + // The value to write. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + //[CLSCompliant (false)] + public static void Write (ulong value) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified 64-bit signed integer value to + // the standard output stream. + // + // Parameters: + // value: + // The value to write. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + public static void Write (long value) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified objects to the standard output + // stream using the specified format information. + // + // Parameters: + // format: + // A composite format string (see Remarks). + // + // arg0: + // The first object to write using format. + // + // arg1: + // The second object to write using format. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + // + // T:System.ArgumentNullException: + // format is null. + // + // T:System.FormatException: + // The format specification in format is invalid. + public static void Write (string format, object arg0, object arg1) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified 32-bit signed integer value to + // the standard output stream. + // + // Parameters: + // value: + // The value to write. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + public static void Write (int value) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified object to the standard output + // stream using the specified format information. + // + // Parameters: + // format: + // A composite format string (see Remarks). + // + // arg0: + // An object to write using format. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + // + // T:System.ArgumentNullException: + // format is null. + // + // T:System.FormatException: + // The format specification in format is invalid. + public static void Write (string format, object arg0) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified 32-bit unsigned integer value + // to the standard output stream. + // + // Parameters: + // value: + // The value to write. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + //[CLSCompliant (false)] + public static void Write (uint value) + { + throw new NotImplementedException (); + } + + //[CLSCompliant (false)] + public static void Write (string format, object arg0, object arg1, object arg2, object arg3) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified array of objects to the standard + // output stream using the specified format information. + // + // Parameters: + // format: + // A composite format string (see Remarks). + // + // arg: + // An array of objects to write using format. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + // + // T:System.ArgumentNullException: + // format or arg is null. + // + // T:System.FormatException: + // The format specification in format is invalid. + public static void Write (string format, params object [] arg) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified Boolean value to the standard + // output stream. + // + // Parameters: + // value: + // The value to write. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + public static void Write (bool value) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the specified Unicode character value to the standard output stream. + // + // Parameters: + // value: + // The value to write. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + public static void Write (char value) + { + _buffer [CursorLeft, CursorTop] = value; + } + + // + // Summary: + // Writes the specified array of Unicode characters to the standard output stream. + // + // Parameters: + // buffer: + // A Unicode character array. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + public static void Write (char [] buffer) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the specified subarray of Unicode characters to the standard output stream. + // + // Parameters: + // buffer: + // An array of Unicode characters. + // + // index: + // The starting position in buffer. + // + // count: + // The number of characters to write. + // + // Exceptions: + // T:System.ArgumentNullException: + // buffer is null. + // + // T:System.ArgumentOutOfRangeException: + // index or count is less than zero. + // + // T:System.ArgumentException: + // index plus count specify a position that is not within buffer. + // + // T:System.IO.IOException: + // An I/O error occurred. + public static void Write (char [] buffer, int index, int count) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified objects to the standard output + // stream using the specified format information. + // + // Parameters: + // format: + // A composite format string (see Remarks). + // + // arg0: + // The first object to write using format. + // + // arg1: + // The second object to write using format. + // + // arg2: + // The third object to write using format. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + // + // T:System.ArgumentNullException: + // format is null. + // + // T:System.FormatException: + // The format specification in format is invalid. + public static void Write (string format, object arg0, object arg1, object arg2) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified System.Decimal value to the standard + // output stream. + // + // Parameters: + // value: + // The value to write. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + public static void Write (decimal value) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified single-precision floating-point + // value to the standard output stream. + // + // Parameters: + // value: + // The value to write. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + public static void Write (float value) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified double-precision floating-point + // value to the standard output stream. + // + // Parameters: + // value: + // The value to write. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + public static void Write (double value) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the current line terminator to the standard output stream. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + public static void WriteLine () + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified single-precision floating-point + // value, followed by the current line terminator, to the standard output stream. + // + // Parameters: + // value: + // The value to write. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + public static void WriteLine (float value) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified 32-bit signed integer value, + // followed by the current line terminator, to the standard output stream. + // + // Parameters: + // value: + // The value to write. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + public static void WriteLine (int value) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified 32-bit unsigned integer value, + // followed by the current line terminator, to the standard output stream. + // + // Parameters: + // value: + // The value to write. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + //[CLSCompliant (false)] + public static void WriteLine (uint value) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified 64-bit signed integer value, + // followed by the current line terminator, to the standard output stream. + // + // Parameters: + // value: + // The value to write. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + public static void WriteLine (long value) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified 64-bit unsigned integer value, + // followed by the current line terminator, to the standard output stream. + // + // Parameters: + // value: + // The value to write. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + //[CLSCompliant (false)] + public static void WriteLine (ulong value) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified object, followed by the current + // line terminator, to the standard output stream. + // + // Parameters: + // value: + // The value to write. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + public static void WriteLine (object value) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the specified string value, followed by the current line terminator, to + // the standard output stream. + // + // Parameters: + // value: + // The value to write. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + public static void WriteLine (string value) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified object, followed by the current + // line terminator, to the standard output stream using the specified format information. + // + // Parameters: + // format: + // A composite format string (see Remarks). + // + // arg0: + // An object to write using format. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + // + // T:System.ArgumentNullException: + // format is null. + // + // T:System.FormatException: + // The format specification in format is invalid. + public static void WriteLine (string format, object arg0) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified objects, followed by the current + // line terminator, to the standard output stream using the specified format information. + // + // Parameters: + // format: + // A composite format string (see Remarks). + // + // arg0: + // The first object to write using format. + // + // arg1: + // The second object to write using format. + // + // arg2: + // The third object to write using format. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + // + // T:System.ArgumentNullException: + // format is null. + // + // T:System.FormatException: + // The format specification in format is invalid. + public static void WriteLine (string format, object arg0, object arg1, object arg2) + { + throw new NotImplementedException (); + } + + //[CLSCompliant (false)] + public static void WriteLine (string format, object arg0, object arg1, object arg2, object arg3) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified array of objects, followed by + // the current line terminator, to the standard output stream using the specified + // format information. + // + // Parameters: + // format: + // A composite format string (see Remarks). + // + // arg: + // An array of objects to write using format. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + // + // T:System.ArgumentNullException: + // format or arg is null. + // + // T:System.FormatException: + // The format specification in format is invalid. + public static void WriteLine (string format, params object [] arg) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the specified subarray of Unicode characters, followed by the current + // line terminator, to the standard output stream. + // + // Parameters: + // buffer: + // An array of Unicode characters. + // + // index: + // The starting position in buffer. + // + // count: + // The number of characters to write. + // + // Exceptions: + // T:System.ArgumentNullException: + // buffer is null. + // + // T:System.ArgumentOutOfRangeException: + // index or count is less than zero. + // + // T:System.ArgumentException: + // index plus count specify a position that is not within buffer. + // + // T:System.IO.IOException: + // An I/O error occurred. + public static void WriteLine (char [] buffer, int index, int count) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified System.Decimal value, followed + // by the current line terminator, to the standard output stream. + // + // Parameters: + // value: + // The value to write. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + public static void WriteLine (decimal value) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the specified array of Unicode characters, followed by the current line + // terminator, to the standard output stream. + // + // Parameters: + // buffer: + // A Unicode character array. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + public static void WriteLine (char [] buffer) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the specified Unicode character, followed by the current line terminator, + // value to the standard output stream. + // + // Parameters: + // value: + // The value to write. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + public static void WriteLine (char value) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified Boolean value, followed by the + // current line terminator, to the standard output stream. + // + // Parameters: + // value: + // The value to write. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + public static void WriteLine (bool value) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified objects, followed by the current + // line terminator, to the standard output stream using the specified format information. + // + // Parameters: + // format: + // A composite format string (see Remarks). + // + // arg0: + // The first object to write using format. + // + // arg1: + // The second object to write using format. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + // + // T:System.ArgumentNullException: + // format is null. + // + // T:System.FormatException: + // The format specification in format is invalid. + public static void WriteLine (string format, object arg0, object arg1) + { + throw new NotImplementedException (); + } + + // + // Summary: + // Writes the text representation of the specified double-precision floating-point + // value, followed by the current line terminator, to the standard output stream. + // + // Parameters: + // value: + // The value to write. + // + // Exceptions: + // T:System.IO.IOException: + // An I/O error occurred. + public static void WriteLine (double value) + { + throw new NotImplementedException (); + } + + } +} diff --git a/Terminal.Gui/ConsoleDrivers/MockDriver/MockDriver.cs b/Terminal.Gui/ConsoleDrivers/MockDriver/MockDriver.cs new file mode 100644 index 000000000..c236cd0b9 --- /dev/null +++ b/Terminal.Gui/ConsoleDrivers/MockDriver/MockDriver.cs @@ -0,0 +1,440 @@ +// +// MockDriver.cs: A mock ConsoleDriver for unit tests. +// +// Authors: +// Charlie Kindel (github.com/tig) +// +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using NStack; + +namespace Terminal.Gui { + public class MockDriver : ConsoleDriver, IMainLoopDriver { + int cols, rows; + public override int Cols => cols; + public override int Rows => rows; + + // The format is rows, columns and 3 values on the last column: Rune, Attribute and Dirty Flag + int [,,] contents; + bool [] dirtyLine; + + void UpdateOffscreen () + { + int cols = Cols; + int rows = Rows; + + contents = new int [rows, cols, 3]; + for (int r = 0; r < rows; r++) { + for (int c = 0; c < cols; c++) { + contents [r, c, 0] = ' '; + contents [r, c, 1] = MakeColor (ConsoleColor.Gray, ConsoleColor.Black); + contents [r, c, 2] = 0; + } + } + dirtyLine = new bool [rows]; + for (int row = 0; row < rows; row++) + dirtyLine [row] = true; + } + + static bool sync = false; + + public MockDriver () + { + cols = MockConsole.WindowWidth; + rows = MockConsole.WindowHeight; // - 1; + UpdateOffscreen (); + } + + bool needMove; + // Current row, and current col, tracked by Move/AddCh only + int ccol, crow; + public override void Move (int col, int row) + { + ccol = col; + crow = row; + + if (Clip.Contains (col, row)) { + MockConsole.CursorTop = row; + MockConsole.CursorLeft = col; + needMove = false; + } else { + MockConsole.CursorTop = Clip.Y; + MockConsole.CursorLeft = Clip.X; + needMove = true; + } + + } + + public override void AddRune (Rune rune) + { + if (Clip.Contains (ccol, crow)) { + if (needMove) { + //MockConsole.CursorLeft = ccol; + //MockConsole.CursorTop = crow; + needMove = false; + } + contents [crow, ccol, 0] = (int)(uint)rune; + contents [crow, ccol, 1] = currentAttribute; + contents [crow, ccol, 2] = 1; + dirtyLine [crow] = true; + } else + needMove = true; + ccol++; + //if (ccol == Cols) { + // ccol = 0; + // if (crow + 1 < Rows) + // crow++; + //} + if (sync) + UpdateScreen (); + } + + public override void AddStr (ustring str) + { + foreach (var rune in str) + AddRune (rune); + } + + public override void End () + { + MockConsole.ResetColor (); + MockConsole.Clear (); + } + + static Attribute MakeColor (ConsoleColor f, ConsoleColor b) + { + // Encode the colors into the int value. + return new Attribute () { value = ((((int)f) & 0xffff) << 16) | (((int)b) & 0xffff) }; + } + + + public override void Init (Action terminalResized) + { + Colors.TopLevel = new ColorScheme (); + Colors.Base = new ColorScheme (); + Colors.Dialog = new ColorScheme (); + Colors.Menu = new ColorScheme (); + Colors.Error = new ColorScheme (); + Clip = new Rect (0, 0, Cols, Rows); + + Colors.TopLevel.Normal = MakeColor (ConsoleColor.Green, ConsoleColor.Black); + Colors.TopLevel.Focus = MakeColor (ConsoleColor.White, ConsoleColor.DarkCyan); + Colors.TopLevel.HotNormal = MakeColor (ConsoleColor.DarkYellow, ConsoleColor.Black); + Colors.TopLevel.HotFocus = MakeColor (ConsoleColor.DarkBlue, ConsoleColor.DarkCyan); + + Colors.Base.Normal = MakeColor (ConsoleColor.White, ConsoleColor.Blue); + Colors.Base.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.Cyan); + Colors.Base.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.Blue); + Colors.Base.HotFocus = MakeColor (ConsoleColor.Yellow, ConsoleColor.Cyan); + + // Focused, + // Selected, Hot: Yellow on Black + // Selected, text: white on black + // Unselected, hot: yellow on cyan + // unselected, text: same as unfocused + Colors.Menu.HotFocus = MakeColor (ConsoleColor.Yellow, ConsoleColor.Black); + Colors.Menu.Focus = MakeColor (ConsoleColor.White, ConsoleColor.Black); + Colors.Menu.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.Cyan); + Colors.Menu.Normal = MakeColor (ConsoleColor.White, ConsoleColor.Cyan); + Colors.Menu.Disabled = MakeColor (ConsoleColor.DarkGray, ConsoleColor.Cyan); + + Colors.Dialog.Normal = MakeColor (ConsoleColor.Black, ConsoleColor.Gray); + Colors.Dialog.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.Cyan); + Colors.Dialog.HotNormal = MakeColor (ConsoleColor.Blue, ConsoleColor.Gray); + Colors.Dialog.HotFocus = MakeColor (ConsoleColor.Blue, ConsoleColor.Cyan); + + Colors.Error.Normal = MakeColor (ConsoleColor.White, ConsoleColor.Red); + Colors.Error.Focus = MakeColor (ConsoleColor.Black, ConsoleColor.Gray); + Colors.Error.HotNormal = MakeColor (ConsoleColor.Yellow, ConsoleColor.Red); + Colors.Error.HotFocus = Colors.Error.HotNormal; + + HLine = '\u2500'; + VLine = '\u2502'; + Stipple = '\u2592'; + Diamond = '\u25c6'; + ULCorner = '\u250C'; + LLCorner = '\u2514'; + URCorner = '\u2510'; + LRCorner = '\u2518'; + LeftTee = '\u251c'; + RightTee = '\u2524'; + TopTee = '\u22a4'; + BottomTee = '\u22a5'; + Checked = '\u221a'; + UnChecked = ' '; + Selected = '\u25cf'; + UnSelected = '\u25cc'; + RightArrow = '\u25ba'; + LeftArrow = '\u25c4'; + UpArrow = '\u25b2'; + DownArrow = '\u25bc'; + LeftDefaultIndicator = '\u25e6'; + RightDefaultIndicator = '\u25e6'; + LeftBracket = '['; + RightBracket = ']'; + OnMeterSegment = '\u258c'; + OffMeterSegement = ' '; + + //MockConsole.Clear (); + } + + public override Attribute MakeAttribute (Color fore, Color back) + { + return MakeColor ((ConsoleColor)fore, (ConsoleColor)back); + } + + int redrawColor = -1; + void SetColor (int color) + { + redrawColor = color; + IEnumerable values = Enum.GetValues (typeof (ConsoleColor)) + .OfType () + .Select (s => (int)s); + if (values.Contains (color & 0xffff)) { + MockConsole.BackgroundColor = (ConsoleColor)(color & 0xffff); + } + if (values.Contains ((color >> 16) & 0xffff)) { + MockConsole.ForegroundColor = (ConsoleColor)((color >> 16) & 0xffff); + } + } + + public override void UpdateScreen () + { + int rows = Rows; + int cols = Cols; + + MockConsole.CursorTop = 0; + MockConsole.CursorLeft = 0; + for (int row = 0; row < rows; row++) { + dirtyLine [row] = false; + for (int col = 0; col < cols; col++) { + contents [row, col, 2] = 0; + var color = contents [row, col, 1]; + if (color != redrawColor) + SetColor (color); + MockConsole.Write ((char)contents [row, col, 0]); + } + } + } + + public override void Refresh () + { + int rows = Rows; + int cols = Cols; + + var savedRow = MockConsole.CursorTop; + var savedCol = MockConsole.CursorLeft; + for (int row = 0; row < rows; row++) { + if (!dirtyLine [row]) + continue; + dirtyLine [row] = false; + for (int col = 0; col < cols; col++) { + if (contents [row, col, 2] != 1) + continue; + + MockConsole.CursorTop = row; + MockConsole.CursorLeft = col; + for (; col < cols && contents [row, col, 2] == 1; col++) { + var color = contents [row, col, 1]; + if (color != redrawColor) + SetColor (color); + + MockConsole.Write ((char)contents [row, col, 0]); + contents [row, col, 2] = 0; + } + } + } + MockConsole.CursorTop = savedRow; + MockConsole.CursorLeft = savedCol; + } + + public override void UpdateCursor () + { + // + } + + public override void StartReportingMouseMoves () + { + } + + public override void StopReportingMouseMoves () + { + } + + public override void Suspend () + { + } + + int currentAttribute; + public override void SetAttribute (Attribute c) + { + currentAttribute = c.value; + } + + Key MapKey (ConsoleKeyInfo keyInfo) + { + switch (keyInfo.Key) { + case ConsoleKey.Escape: + return Key.Esc; + case ConsoleKey.Tab: + return keyInfo.Modifiers == ConsoleModifiers.Shift ? Key.BackTab : Key.Tab; + case ConsoleKey.Home: + return Key.Home; + case ConsoleKey.End: + return Key.End; + case ConsoleKey.LeftArrow: + return Key.CursorLeft; + case ConsoleKey.RightArrow: + return Key.CursorRight; + case ConsoleKey.UpArrow: + return Key.CursorUp; + case ConsoleKey.DownArrow: + return Key.CursorDown; + case ConsoleKey.PageUp: + return Key.PageUp; + case ConsoleKey.PageDown: + return Key.PageDown; + case ConsoleKey.Enter: + return Key.Enter; + case ConsoleKey.Spacebar: + return Key.Space; + case ConsoleKey.Backspace: + return Key.Backspace; + case ConsoleKey.Delete: + return Key.Delete; + + case ConsoleKey.Oem1: + case ConsoleKey.Oem2: + case ConsoleKey.Oem3: + case ConsoleKey.Oem4: + case ConsoleKey.Oem5: + case ConsoleKey.Oem6: + case ConsoleKey.Oem7: + case ConsoleKey.Oem8: + case ConsoleKey.Oem102: + case ConsoleKey.OemPeriod: + case ConsoleKey.OemComma: + case ConsoleKey.OemPlus: + case ConsoleKey.OemMinus: + return (Key)((uint)keyInfo.KeyChar); + } + + var key = keyInfo.Key; + if (key >= ConsoleKey.A && key <= ConsoleKey.Z) { + var delta = key - ConsoleKey.A; + if (keyInfo.Modifiers == ConsoleModifiers.Control) + return (Key)((uint)Key.ControlA + delta); + if (keyInfo.Modifiers == ConsoleModifiers.Alt) + return (Key)(((uint)Key.AltMask) | ((uint)'A' + delta)); + if (keyInfo.Modifiers == ConsoleModifiers.Shift) + return (Key)((uint)'A' + delta); + else + return (Key)((uint)'a' + delta); + } + if (key >= ConsoleKey.D0 && key <= ConsoleKey.D9) { + var delta = key - ConsoleKey.D0; + if (keyInfo.Modifiers == ConsoleModifiers.Alt) + return (Key)(((uint)Key.AltMask) | ((uint)'0' + delta)); + if (keyInfo.Modifiers == ConsoleModifiers.Shift) + return (Key)((uint)keyInfo.KeyChar); + return (Key)((uint)'0' + delta); + } + if (key >= ConsoleKey.F1 && key <= ConsoleKey.F10) { + var delta = key - ConsoleKey.F1; + + return (Key)((int)Key.F1 + delta); + } + return (Key)(0xffffffff); + } + + KeyModifiers keyModifiers = new KeyModifiers (); + + public override void PrepareToRun (MainLoop mainLoop, Action keyHandler, Action keyDownHandler, Action keyUpHandler, Action mouseHandler) + { + // Note: Net doesn't support keydown/up events and thus any passed keyDown/UpHandlers will never be called + (mainLoop.Driver as MockDriver).WindowsKeyPressed = delegate (ConsoleKeyInfo consoleKey) { + var map = MapKey (consoleKey); + if (map == (Key)0xffffffff) + return; + keyHandler (new KeyEvent (map, keyModifiers)); + keyUpHandler (new KeyEvent (map, keyModifiers)); + }; + } + + public override void SetColors (ConsoleColor foreground, ConsoleColor background) + { + throw new NotImplementedException (); + } + + public override void SetColors (short foregroundColorId, short backgroundColorId) + { + throw new NotImplementedException (); + } + + public override void CookMouse () + { + } + + public override void UncookMouse () + { + } + + AutoResetEvent keyReady = new AutoResetEvent (false); + AutoResetEvent waitForProbe = new AutoResetEvent (false); + ConsoleKeyInfo? windowsKeyResult = null; + public Action WindowsKeyPressed; + MainLoop mainLoop; + + void WindowsKeyReader () + { + while (true) { + waitForProbe.WaitOne (); + windowsKeyResult = MockConsole.ReadKey (true); + keyReady.Set (); + } + } + + void IMainLoopDriver.Setup (MainLoop mainLoop) + { + this.mainLoop = mainLoop; + Thread readThread = new Thread (WindowsKeyReader); + readThread.Start (); + } + + void IMainLoopDriver.Wakeup () + { + } + + bool IMainLoopDriver.EventsPending (bool wait) + { + long now = DateTime.UtcNow.Ticks; + + int waitTimeout; + if (mainLoop.timeouts.Count > 0) { + waitTimeout = (int)((mainLoop.timeouts.Keys [0] - now) / TimeSpan.TicksPerMillisecond); + if (waitTimeout < 0) + return true; + } else + waitTimeout = -1; + + if (!wait) + waitTimeout = 0; + + windowsKeyResult = null; + waitForProbe.Set (); + keyReady.WaitOne (waitTimeout); + return windowsKeyResult.HasValue; + } + + void IMainLoopDriver.MainIteration () + { + if (windowsKeyResult.HasValue) { + if (WindowsKeyPressed != null) + WindowsKeyPressed (windowsKeyResult.Value); + windowsKeyResult = null; + } + } + } +} \ No newline at end of file diff --git a/Terminal.Gui/Core/Application.cs b/Terminal.Gui/Core/Application.cs index 9b728dc7c..53aff5e82 100644 --- a/Terminal.Gui/Core/Application.cs +++ b/Terminal.Gui/Core/Application.cs @@ -157,21 +157,28 @@ namespace Terminal.Gui { /// Creates a and assigns it to and /// /// - public static void Init () => Init (() => Toplevel.Create ()); + public static void Init (ConsoleDriver driver = null) => Init (() => Toplevel.Create (), driver); internal static bool _initialized = false; /// /// Initializes the Terminal.Gui application /// - static void Init (Func topLevelFactory) + static void Init (Func topLevelFactory, ConsoleDriver driver = null) { if (_initialized) return; + // This supports Unit Tests and the passing of a mock driver/loopdriver + if (driver != null) { + Driver = driver; + Driver.Init (TerminalResized); + MainLoop = new MainLoop ((IMainLoopDriver)driver); + SynchronizationContext.SetSynchronizationContext (new MainLoopSyncContext (MainLoop)); + } + if (Driver == null) { var p = Environment.OSVersion.Platform; IMainLoopDriver mainLoopDriver; - if (UseSystemConsole) { mainLoopDriver = new NetMainLoop (); Driver = new NetDriver (); @@ -199,7 +206,11 @@ namespace Terminal.Gui { public class RunState : IDisposable { internal bool closeDriver = true; - internal RunState (Toplevel view) + /// + /// Initializes a new class. + /// + /// + public RunState (Toplevel view) { Toplevel = view; } @@ -476,7 +487,7 @@ namespace Terminal.Gui { } /// - /// Shutdown an application initialized with + /// Shutdown an application initialized with /// /// /// trueCloses the application.falseCloses toplevels only. public static void Shutdown (bool closeDriver = true) diff --git a/Terminal.Gui/Core/Toplevel.cs b/Terminal.Gui/Core/Toplevel.cs index ec041fa62..7c5db8966 100644 --- a/Terminal.Gui/Core/Toplevel.cs +++ b/Terminal.Gui/Core/Toplevel.cs @@ -20,7 +20,7 @@ namespace Terminal.Gui { /// been called (which sets the property to false). /// /// - /// A Toplevel is created when an application initialzies Terminal.Gui by callling . + /// A Toplevel is created when an application initialzies Terminal.Gui by callling . /// The application Toplevel can be accessed via . Additional Toplevels can be created /// and run (e.g. s. To run a Toplevel, create the and /// call . diff --git a/Terminal.sln b/Terminal.sln index c5b9ac6bc..6df6d7c65 100644 --- a/Terminal.sln +++ b/Terminal.sln @@ -6,10 +6,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example", "Example\Example. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Terminal.Gui", "Terminal.Gui\Terminal.Gui.csproj", "{00F366F8-DEE4-482C-B9FD-6DB0200B79E5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Designer", "Designer\Designer.csproj", "{1228D992-C801-49BB-839A-7BD28A3FFF0A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Designer", "Designer\Designer.csproj", "{1228D992-C801-49BB-839A-7BD28A3FFF0A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UICatalog", "UICatalog\UICatalog.csproj", "{88979F89-9A42-448F-AE3E-3060145F6375}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{8B901EDE-8974-4820-B100-5226917E2990}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -50,6 +52,14 @@ Global {88979F89-9A42-448F-AE3E-3060145F6375}.Release|Any CPU.Build.0 = Release|Any CPU {88979F89-9A42-448F-AE3E-3060145F6375}.Release|x86.ActiveCfg = Release|Any CPU {88979F89-9A42-448F-AE3E-3060145F6375}.Release|x86.Build.0 = Release|Any CPU + {8B901EDE-8974-4820-B100-5226917E2990}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8B901EDE-8974-4820-B100-5226917E2990}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8B901EDE-8974-4820-B100-5226917E2990}.Debug|x86.ActiveCfg = Debug|Any CPU + {8B901EDE-8974-4820-B100-5226917E2990}.Debug|x86.Build.0 = Debug|Any CPU + {8B901EDE-8974-4820-B100-5226917E2990}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8B901EDE-8974-4820-B100-5226917E2990}.Release|Any CPU.Build.0 = Release|Any CPU + {8B901EDE-8974-4820-B100-5226917E2990}.Release|x86.ActiveCfg = Release|Any CPU + {8B901EDE-8974-4820-B100-5226917E2990}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/UnitTests/ApplicationTests.cs b/UnitTests/ApplicationTests.cs new file mode 100644 index 000000000..1676cdb93 --- /dev/null +++ b/UnitTests/ApplicationTests.cs @@ -0,0 +1,195 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Terminal.Gui; +using Xunit; + +// Alais Console to MockConsole so we don't accidentally use Console +using Console = Terminal.Gui.MockConsole; + +// Since Application is a singleton we can't run tests in parallel +[assembly: CollectionBehavior (DisableTestParallelization = true)] + +namespace Terminal.Gui { + public class ApplicationTests { + [Fact] + public void TestInitShutdown () + { + Assert.Null (Application.Current); + Assert.Null (Application.CurrentView); + Assert.Null (Application.Top); + Assert.Null (Application.MainLoop); + Assert.Null (Application.Driver); + + Application.Init (new MockDriver ()); + Assert.NotNull (Application.Current); + Assert.NotNull (Application.CurrentView); + Assert.NotNull (Application.Top); + Assert.NotNull (Application.MainLoop); + Assert.NotNull (Application.Driver); + + // MockDriver is always 80x25 + Assert.Equal (80, Application.Driver.Cols); + Assert.Equal (25, Application.Driver.Rows); + + Application.Shutdown (true); + Assert.Null (Application.Current); + Assert.Null (Application.CurrentView); + Assert.Null (Application.Top); + Assert.Null (Application.MainLoop); + Assert.Null (Application.Driver); + } + + [Fact] + public void TestNewRunState () + { + var rs = new Application.RunState (null); + Assert.NotNull (rs); + + // Should not throw because Toplevel was null + rs.Dispose (); + + var top = new Toplevel (); + rs = new Application.RunState (top); + Assert.NotNull (rs); + + // Should throw because there's no stack + Assert.Throws (() => rs.Dispose ()); + } + + [Fact] + public void TestBeginEnd () + { + // Setup Mock driver + Application.Init (new MockDriver ()); + Assert.NotNull (Application.Driver); + + // Test null Toplevel + Assert.Throws (() => Application.Begin (null)); + + var top = new Toplevel (); + var rs = Application.Begin (top); + Assert.NotNull (rs); + Assert.Equal (top, Application.Current); + Application.End (rs, true); + + Assert.Null (Application.Current); + Assert.Null (Application.CurrentView); + Assert.Null (Application.Top); + Assert.Null (Application.MainLoop); + Assert.Null (Application.Driver); + + Application.Shutdown (true); + } + + [Fact] + public void TestRequestStop () + { + // Setup Mock driver + Application.Init (new MockDriver ()); + Assert.NotNull (Application.Driver); + + var top = new Toplevel (); + var rs = Application.Begin (top); + Assert.NotNull (rs); + Assert.Equal (top, Application.Current); + + Application.Iteration = () => { + Application.RequestStop (); + }; + + Application.Run (top, true); + + Application.Shutdown (true); + Assert.Null (Application.Current); + Assert.Null (Application.CurrentView); + Assert.Null (Application.Top); + Assert.Null (Application.MainLoop); + Assert.Null (Application.Driver); + } + + [Fact] + public void TestRunningFalse () + { + // Setup Mock driver + Application.Init (new MockDriver ()); + Assert.NotNull (Application.Driver); + + var top = new Toplevel (); + var rs = Application.Begin (top); + Assert.NotNull (rs); + Assert.Equal (top, Application.Current); + + Application.Iteration = () => { + top.Running = false; + }; + + Application.Run (top, true); + + Application.Shutdown (true); + Assert.Null (Application.Current); + Assert.Null (Application.CurrentView); + Assert.Null (Application.Top); + Assert.Null (Application.MainLoop); + Assert.Null (Application.Driver); + } + + + [Fact] + public void TestKeyUp () + { + // Setup Mock driver + Application.Init (new MockDriver ()); + Assert.NotNull (Application.Driver); + + // Setup some fake kepresses (This) + var input = "Tests"; + + // Put a control-q in at the end + Console.MockKeyPresses.Push (new ConsoleKeyInfo ('q', ConsoleKey.Q, shift: false, alt: false, control: true)); + foreach (var c in input.Reverse()) { + if (char.IsLetter (c)) { + Console.MockKeyPresses.Push (new ConsoleKeyInfo (char.ToLower (c), (ConsoleKey)char.ToUpper (c), shift: char.IsUpper (c), alt: false, control: false)); + } + else + { + Console.MockKeyPresses.Push (new ConsoleKeyInfo (c, (ConsoleKey)c, shift: false, alt: false, control: false)); + } + } + + int stackSize = Console.MockKeyPresses.Count; + + int iterations = 0; + Application.Iteration = () => { + iterations++; + }; + + int keyUps = 0; + var output = string.Empty; + Application.Top.KeyUp += (View.KeyEventEventArgs args) => { + if (args.KeyEvent.Key != Key.ControlQ) { + output += (char)args.KeyEvent.KeyValue; + } + keyUps++; + }; + + Application.Run (Application.Top, true); + + // Input string should match output + Assert.Equal (input, output); + + // # of key up events should match stack size + Assert.Equal (stackSize, keyUps); + + // # of key up events should match # of iterations + Assert.Equal (stackSize, iterations); + + Application.Shutdown (true); + Assert.Null (Application.Current); + Assert.Null (Application.CurrentView); + Assert.Null (Application.Top); + Assert.Null (Application.MainLoop); + Assert.Null (Application.Driver); + } + } +} diff --git a/UnitTests/ConsoleDriverTests.cs b/UnitTests/ConsoleDriverTests.cs new file mode 100644 index 000000000..b2b040e70 --- /dev/null +++ b/UnitTests/ConsoleDriverTests.cs @@ -0,0 +1,67 @@ +using System; +using Terminal.Gui; +using Xunit; + +// Alais Console to MockConsole so we don't accidentally use Console +using Console = Terminal.Gui.MockConsole; + +namespace Terminal.Gui { + public class ConsoleDriverTests { + [Fact] + public void TestInit () + { + var driver = new MockDriver (); + driver.Init (() => { }); + + Assert.Equal (80, Console.BufferWidth); + Assert.Equal (25, Console.BufferHeight); + + // MockDriver is always 80x25 + Assert.Equal (Console.BufferWidth, driver.Cols); + Assert.Equal (Console.BufferHeight, driver.Rows); + driver.End (); + } + + [Fact] + public void TestEnd () + { + var driver = new MockDriver (); + driver.Init (() => { }); + + MockConsole.ForegroundColor = ConsoleColor.Red; + Assert.Equal (ConsoleColor.Red, Console.ForegroundColor); + + MockConsole.BackgroundColor = ConsoleColor.Green; + Assert.Equal (ConsoleColor.Green, Console.BackgroundColor); + driver.Move (2, 3); + Assert.Equal (2, Console.CursorLeft); + Assert.Equal (3, Console.CursorTop); + + driver.End (); + Assert.Equal (0, Console.CursorLeft); + Assert.Equal (0, Console.CursorTop); + Assert.Equal (ConsoleColor.Gray, Console.ForegroundColor); + Assert.Equal (ConsoleColor.Black, Console.BackgroundColor); + } + + [Fact] + public void TestSetColors () + { + var driver = new MockDriver (); + driver.Init (() => { }); + Assert.Equal (ConsoleColor.Gray, Console.ForegroundColor); + Assert.Equal (ConsoleColor.Black, Console.BackgroundColor); + + Console.ForegroundColor = ConsoleColor.Red; + Assert.Equal (ConsoleColor.Red, Console.ForegroundColor); + + Console.BackgroundColor = ConsoleColor.Green; + Assert.Equal (ConsoleColor.Green, Console.BackgroundColor); + + Console.ResetColor (); + Assert.Equal (ConsoleColor.Gray, Console.ForegroundColor); + Assert.Equal (ConsoleColor.Black, Console.BackgroundColor); + driver.End (); + } + } +} diff --git a/UnitTests/UnitTests.csproj b/UnitTests/UnitTests.csproj new file mode 100644 index 000000000..9b10745f5 --- /dev/null +++ b/UnitTests/UnitTests.csproj @@ -0,0 +1,20 @@ + + + + netcoreapp3.1 + false + + + + + + + + + + + + + + + diff --git a/UnitTests/xunit.runner.json b/UnitTests/xunit.runner.json new file mode 100644 index 000000000..e810a9725 --- /dev/null +++ b/UnitTests/xunit.runner.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json", + "parallelizeTestCollections": false, + "parallelizeAssembly": false +}