Browse Source

Code coverage (#1235)

* tweaked version # for v1.0.0-beta.10

* tweaked version # for v1.0.0-beta.11

* Updated readme and revision history for 1.0

* excluding test results

* Added support for viewing code coverage results with Fine Code Coverage

* add generating CC to CI/CD

* refactored unit test namespaces

* more refactoring. commented out failing test.

* Removed UnitTests and UICatalog from code coverage reporting

* made Application and test more deterministic

* disabled Multi_Thread_Toplevels because it is currently broken and don't understand why

* updated threading test per @bdisp

* testing cc badge stuff

* another test

* using coverlet.settings

* trying copy

* trying cp. duh.

* trying mv.

* wrong path

* print

* chaging badge output for testing

* yaml error

* fixed code coverage

* moved dimtests to core
Charlie Kindel 4 years ago
parent
commit
b29240f362

+ 25 - 2
.github/workflows/dotnet-core.yml

@@ -1,4 +1,4 @@
-name: .NET Core
+name: Build Terminal.Gui with .NET Core
 
 
 on:
 on:
   push:
   push:
@@ -13,13 +13,36 @@ jobs:
 
 
     steps:
     steps:
     - uses: actions/checkout@v2
     - uses: actions/checkout@v2
+
     - name: Setup .NET Core
     - name: Setup .NET Core
       uses: actions/setup-dotnet@v1
       uses: actions/setup-dotnet@v1
       with:
       with:
         dotnet-version: 5.0.100
         dotnet-version: 5.0.100
+
     - name: Install dependencies
     - name: Install dependencies
       run: dotnet restore
       run: dotnet restore
+
     - name: Build
     - name: Build
       run: dotnet build --configuration Release --no-restore
       run: dotnet build --configuration Release --no-restore
+
     - name: Test
     - name: Test
-      run: dotnet test --no-restore --verbosity normal
+      run: |
+        dotnet test --no-restore --verbosity normal --collect:"XPlat Code Coverage"  --settings UnitTests/coverlet.runsettings
+        mv -v UnitTests/TestResults/*/*.* UnitTests/TestResults/
+
+    - name: Create Test Coverage Badge
+      uses: simon-k/[email protected]
+      id: create_coverage_badge
+      with:
+        label: Unit Test Coverage
+        color: brightgreen
+        path: UnitTests/TestResults/coverage.opencover.xml
+        gist-filename: code-coverage.json
+        # https://gist.github.com/migueldeicaza/90ef67a684cb71db1817921a970f8d27
+        gist-id: 90ef67a684cb71db1817921a970f8d27
+        gist-auth-token: ${{ secrets.GIST_AUTH_TOKEN }}   
+
+    - name: Print Code Coverage
+      run: |
+        echo "Code coverage percentage: ${{steps.create_coverage_badge.outputs.percentage}}%"
+        echo "Badge data: ${{steps.create_coverage_badge.outputs.badge}}"

+ 2 - 0
.gitignore

@@ -10,6 +10,8 @@ packages
 
 
 docfx/api
 docfx/api
 
 
+UnitTests/TestResults
+
 #git merge files
 #git merge files
 *.orig
 *.orig
 
 

+ 2 - 5
README.md

@@ -1,6 +1,7 @@
 ![.NET Core](https://github.com/migueldeicaza/gui.cs/workflows/.NET%20Core/badge.svg?branch=master)
 ![.NET Core](https://github.com/migueldeicaza/gui.cs/workflows/.NET%20Core/badge.svg?branch=master)
 ![Code scanning - action](https://github.com/migueldeicaza/gui.cs/workflows/Code%20scanning%20-%20action/badge.svg)
 ![Code scanning - action](https://github.com/migueldeicaza/gui.cs/workflows/Code%20scanning%20-%20action/badge.svg)
 [![Version](https://img.shields.io/nuget/v/Terminal.Gui.svg)](https://www.nuget.org/packages/Terminal.Gui)
 [![Version](https://img.shields.io/nuget/v/Terminal.Gui.svg)](https://www.nuget.org/packages/Terminal.Gui)
+![Code Coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/migueldeicaza/90ef67a684cb71db1817921a970f8d27/raw/a315df88b9a7b81136b708bd669614099dd95979/code-coverage.json)
 [![Downloads](https://img.shields.io/nuget/dt/Terminal.Gui)](https://www.nuget.org/packages/Terminal.Gui)
 [![Downloads](https://img.shields.io/nuget/dt/Terminal.Gui)](https://www.nuget.org/packages/Terminal.Gui)
 [![License](https://img.shields.io/github/license/migueldeicaza/gui.cs.svg)](LICENSE)
 [![License](https://img.shields.io/github/license/migueldeicaza/gui.cs.svg)](LICENSE)
 
 
@@ -10,10 +11,6 @@ A simple toolkit for building console GUI apps for .NET, .NET Core, and Mono tha
 
 
 ![Sample app](https://raw.githubusercontent.com/migueldeicaza/gui.cs/master/docfx/sample.gif)
 ![Sample app](https://raw.githubusercontent.com/migueldeicaza/gui.cs/master/docfx/sample.gif)
 
 
-The most recent released [Nuget package is version `0.90.x`](https://www.nuget.org/packages/Terminal.Gui) which is the "Stable, Feature Complete" pre-release of 1.0.
-
-Nuget also contains pre-release versions of 1.0; they are identified with `-pre` or `-beta` in the version number (e.g. `1.0.0-pre.1`)
-
 ## Controls & Features
 ## Controls & Features
 
 
 *Terminal.Gui* contains various controls for building text user interfaces:
 *Terminal.Gui* contains various controls for building text user interfaces:
@@ -222,4 +219,4 @@ A presentation of this was part of the [Retro.NET](https://channel9.msdn.com/Eve
 
 
 Release history can be found in the [Terminal.Gui.csproj](https://github.com/migueldeicaza/gui.cs/blob/master/Terminal.Gui/Terminal.Gui.csproj) file.
 Release history can be found in the [Terminal.Gui.csproj](https://github.com/migueldeicaza/gui.cs/blob/master/Terminal.Gui/Terminal.Gui.csproj) file.
 
 
-In 2019 and 2020, Charlie Kindel (https://github.com/tig) and @BDisp (https://github.com/BDisp) vastly extended, improved, polished and fixed gui.cs to what it is today.
+In 2019, 2020, and 2021, Charlie Kindel (https://github.com/tig), @BDisp (https://github.com/BDisp), and Thomas Nind (https://github.com/tznind) vastly extended, improved, polished and fixed gui.cs to what it is today.

+ 16 - 0
Terminal.Gui/Core/Application.cs

@@ -208,6 +208,9 @@ namespace Terminal.Gui {
 //			System.Diagnostics.Debugger.Break ();
 //			System.Diagnostics.Debugger.Break ();
 //#endif
 //#endif
 
 
+			// Reset all class variables (Application is a singleton).
+			ResetState ();
+
 			// This supports Unit Tests and the passing of a mock driver/loopdriver
 			// This supports Unit Tests and the passing of a mock driver/loopdriver
 			if (driver != null) {
 			if (driver != null) {
 				if (mainLoopDriver == null) {
 				if (mainLoopDriver == null) {
@@ -523,6 +526,14 @@ namespace Terminal.Gui {
 		/// </summary>
 		/// </summary>
 		public static void Shutdown ()
 		public static void Shutdown ()
 		{
 		{
+			ResetState ();
+		}
+
+		// Encapsulate all setting of initial state for Application; Having
+		// this in a function like this ensures we don't make mistakes in
+		// guranteeing that the state of this singleton is deterministic when Init
+		// starts running and after Shutdown returns.
+		static void ResetState () {
 			// Shutdown is the bookend for Init. As such it needs to clean up all resources
 			// Shutdown is the bookend for Init. As such it needs to clean up all resources
 			// Init created. Apps that do any threading will need to code defensively for this.
 			// Init created. Apps that do any threading will need to code defensively for this.
 			// e.g. see Issue #537
 			// e.g. see Issue #537
@@ -538,6 +549,10 @@ namespace Terminal.Gui {
 			MainLoop = null;
 			MainLoop = null;
 			Driver?.End ();
 			Driver?.End ();
 			Driver = null;
 			Driver = null;
+			Iteration = null;
+			UseSystemConsole = false;
+			RootMouseEvent = null;
+			Resized = null;
 			_initialized = false;
 			_initialized = false;
 
 
 			// Reset synchronization context to allow the user to run async/await,
 			// Reset synchronization context to allow the user to run async/await,
@@ -547,6 +562,7 @@ namespace Terminal.Gui {
 			SynchronizationContext.SetSynchronizationContext (syncContext: null);
 			SynchronizationContext.SetSynchronizationContext (syncContext: null);
 		}
 		}
 
 
+
 		static void Redraw (View view)
 		static void Redraw (View view)
 		{
 		{
 			view.Redraw (view.Bounds);
 			view.Redraw (view.Bounds);

+ 0 - 2
Terminal.Gui/Terminal.Gui.csproj

@@ -5,8 +5,6 @@
     <AssemblyName>Terminal.Gui</AssemblyName>
     <AssemblyName>Terminal.Gui</AssemblyName>
     <DocumentationFile>bin\Release\Terminal.Gui.xml</DocumentationFile>
     <DocumentationFile>bin\Release\Terminal.Gui.xml</DocumentationFile>
     <GenerateDocumentationFile Condition=" '$(Configuration)' == 'Release' ">true</GenerateDocumentationFile>
     <GenerateDocumentationFile Condition=" '$(Configuration)' == 'Release' ">true</GenerateDocumentationFile>
-  </PropertyGroup>
-  <PropertyGroup>
     <GeneratePackageOnBuild Condition=" '$(Configuration)' == 'Release' ">true</GeneratePackageOnBuild>
     <GeneratePackageOnBuild Condition=" '$(Configuration)' == 'Release' ">true</GeneratePackageOnBuild>
     <PackageId>Terminal.Gui</PackageId>
     <PackageId>Terminal.Gui</PackageId>
     <PackageLicenseExpression>MIT</PackageLicenseExpression>
     <PackageLicenseExpression>MIT</PackageLicenseExpression>

+ 37 - 38
Terminal.Gui/Views/TableView.cs

@@ -145,6 +145,43 @@ namespace Terminal.Gui {
 	/// </summary>
 	/// </summary>
 	public class TableView : View {
 	public class TableView : View {
 
 
+		/// <summary>
+		///  Defines the event arguments for <see cref="TableView.CellActivated"/> event
+		/// </summary>
+		public class CellActivatedEventArgs : EventArgs {
+			/// <summary>
+			/// The current table to which the new indexes refer.  May be null e.g. if selection change is the result of clearing the table from the view
+			/// </summary>
+			/// <value></value>
+			public DataTable Table { get; }
+
+
+			/// <summary>
+			/// The column index of the <see cref="Table"/> cell that is being activated
+			/// </summary>
+			/// <value></value>
+			public int Col { get; }
+
+			/// <summary>
+			/// The row index of the <see cref="Table"/> cell that is being activated
+			/// </summary>
+			/// <value></value>
+			public int Row { get; }
+
+			/// <summary>
+			/// Creates a new instance of arguments describing a cell being activated in <see cref="TableView"/>
+			/// </summary>
+			/// <param name="t"></param>
+			/// <param name="col"></param>
+			/// <param name="row"></param>
+			public CellActivatedEventArgs (DataTable t, int col, int row)
+			{
+				Table = t;
+				Col = col;
+				Row = row;
+			}
+		}
+
 		private int columnOffset;
 		private int columnOffset;
 		private int rowOffset;
 		private int rowOffset;
 		private int selectedRow;
 		private int selectedRow;
@@ -1307,42 +1344,4 @@ namespace Terminal.Gui {
 			Rect = rect;
 			Rect = rect;
 		}
 		}
 	}
 	}
-	
-	/// <summary>
-	///  Defines the event arguments for <see cref="TableView.CellActivated"/> event
-	/// </summary>
-	public class CellActivatedEventArgs : EventArgs
-	{
-		/// <summary>
-		/// The current table to which the new indexes refer.  May be null e.g. if selection change is the result of clearing the table from the view
-		/// </summary>
-		/// <value></value>
-		public DataTable Table {get;}
-
-
-		/// <summary>
-		/// The column index of the <see cref="Table"/> cell that is being activated
-		/// </summary>
-		/// <value></value>
-		public int Col {get;}
-		
-		/// <summary>
-		/// The row index of the <see cref="Table"/> cell that is being activated
-		/// </summary>
-		/// <value></value>
-		public int Row {get;}
-
-			/// <summary>
-			/// Creates a new instance of arguments describing a cell being activated in <see cref="TableView"/>
-			/// </summary>
-			/// <param name="t"></param>
-			/// <param name="col"></param>
-			/// <param name="row"></param>
-			public CellActivatedEventArgs(DataTable t, int col, int row)
-		{
-			Table = t;
-			Col = col;
-			Row = row;
-		}
-	}
 }
 }

+ 1 - 1
UICatalog/Scenarios/CsvEditor.cs

@@ -504,7 +504,7 @@ namespace UICatalog.Scenarios {
 			enteredText = okPressed? tf.Text.ToString() : null;
 			enteredText = okPressed? tf.Text.ToString() : null;
 			return okPressed;
 			return okPressed;
 		}
 		}
-		private void EditCurrentCell (CellActivatedEventArgs e)
+		private void EditCurrentCell (TableView.CellActivatedEventArgs e)
 		{
 		{
 			if(e.Table == null)
 			if(e.Table == null)
 				return;
 				return;

+ 1 - 1
UICatalog/Scenarios/TableEditor.cs

@@ -273,7 +273,7 @@ namespace UICatalog.Scenarios {
 			tableView.Table = BuildSimpleDataTable(big ? 30 : 5, big ? 1000 : 5);
 			tableView.Table = BuildSimpleDataTable(big ? 30 : 5, big ? 1000 : 5);
 		}
 		}
 
 
-		private void EditCurrentCell (CellActivatedEventArgs e)
+		private void EditCurrentCell (TableView.CellActivatedEventArgs e)
 		{
 		{
 			if(e.Table == null)
 			if(e.Table == null)
 				return;
 				return;

+ 36 - 16
UnitTests/ApplicationTests.cs

@@ -1,18 +1,13 @@
 using System;
 using System;
-using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Threading;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
-using Terminal.Gui;
 using Xunit;
 using Xunit;
 
 
 // Alais Console to MockConsole so we don't accidentally use Console
 // Alais Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-// Since Application is a singleton we can't run tests in parallel
-[assembly: CollectionBehavior (DisableTestParallelization = true)]
-
-namespace Terminal.Gui {
+namespace Terminal.Gui.Core {
 	public class ApplicationTests {
 	public class ApplicationTests {
 		public ApplicationTests ()
 		public ApplicationTests ()
 		{
 		{
@@ -24,26 +19,51 @@ namespace Terminal.Gui {
 		[Fact]
 		[Fact]
 		public void Init_Shutdown_Cleans_Up ()
 		public void Init_Shutdown_Cleans_Up ()
 		{
 		{
-			Assert.Null (Application.Current);
-			Assert.Null (Application.Top);
-			Assert.Null (Application.MainLoop);
-			Assert.Null (Application.Driver);
+			// Verify inital state is per spec
+			Pre_Init_State ();
 
 
 			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
 			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
-			Assert.NotNull (Application.Current);
-			Assert.NotNull (Application.Top);
-			Assert.NotNull (Application.MainLoop);
-			Assert.NotNull (Application.Driver);
+
+			// Verify post-Init state is correct
+			Post_Init_State ();
 
 
 			// MockDriver is always 80x25
 			// MockDriver is always 80x25
 			Assert.Equal (80, Application.Driver.Cols);
 			Assert.Equal (80, Application.Driver.Cols);
 			Assert.Equal (25, Application.Driver.Rows);
 			Assert.Equal (25, Application.Driver.Rows);
 
 
 			Application.Shutdown ();
 			Application.Shutdown ();
-			Assert.Null (Application.Current);
+
+			// Verify state is back to initial
+			Pre_Init_State ();
+
+		}
+
+		void Pre_Init_State ()
+		{
+			Assert.Null (Application.Driver);
 			Assert.Null (Application.Top);
 			Assert.Null (Application.Top);
+			Assert.Null (Application.Current);
+			Assert.Throws<ArgumentNullException> (() => Application.HeightAsBuffer == true);
+			Assert.False (Application.AlwaysSetPosition);
 			Assert.Null (Application.MainLoop);
 			Assert.Null (Application.MainLoop);
-			Assert.Null (Application.Driver);
+			Assert.Null (Application.Iteration);
+			Assert.False (Application.UseSystemConsole);
+			Assert.Null (Application.RootMouseEvent);
+			Assert.Null (Application.Resized);
+		}
+
+		void Post_Init_State ()
+		{
+			Assert.NotNull (Application.Driver);
+			Assert.NotNull (Application.Top);
+			Assert.NotNull (Application.Current);
+			Assert.False (Application.HeightAsBuffer);
+			Assert.False (Application.AlwaysSetPosition);
+			Assert.NotNull (Application.MainLoop);
+			Assert.Null (Application.Iteration);
+			Assert.False (Application.UseSystemConsole);
+			Assert.Null (Application.RootMouseEvent);
+			Assert.Null (Application.Resized);
 		}
 		}
 
 
 		[Fact]
 		[Fact]

+ 4 - 0
UnitTests/AssemblyInfo.cs

@@ -0,0 +1,4 @@
+using Xunit;
+
+// Since Application is a singleton we can't run tests in parallel
+[assembly: CollectionBehavior (DisableTestParallelization = true)]

+ 1 - 1
UnitTests/ConsoleDriverTests.cs

@@ -5,7 +5,7 @@ using Xunit;
 // Alais Console to MockConsole so we don't accidentally use Console
 // Alais Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-namespace Terminal.Gui {
+namespace Terminal.Gui.ConsoleDrivers {
 	public class ConsoleDriverTests {
 	public class ConsoleDriverTests {
 		[Fact]
 		[Fact]
 		public void Init_Inits ()
 		public void Init_Inits ()

+ 1 - 1
UnitTests/DimTests.cs

@@ -11,7 +11,7 @@ using Xunit;
 // Alais Console to MockConsole so we don't accidentally use Console
 // Alais Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-namespace Terminal.Gui {
+namespace Terminal.Gui.Core {
 	public class DimTests {
 	public class DimTests {
 		public DimTests ()
 		public DimTests ()
 		{
 		{

+ 1 - 1
UnitTests/MainLoopTests.cs

@@ -12,7 +12,7 @@ using Xunit.Sdk;
 // Alais Console to MockConsole so we don't accidentally use Console
 // Alais Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-namespace Terminal.Gui {
+namespace Terminal.Gui.Core {
 	public class MainLoopTests {
 	public class MainLoopTests {
 
 
 		[Fact]
 		[Fact]

+ 2 - 2
UnitTests/PointTests.cs

@@ -1,7 +1,7 @@
 using System;
 using System;
 using Xunit;
 using Xunit;
 
 
-namespace Terminal.Gui {
+namespace Terminal.Gui.Types {
 	public class PointTests {
 	public class PointTests {
 		[Fact]
 		[Fact]
 		public void Point_New ()
 		public void Point_New ()
@@ -20,7 +20,7 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		public void Point__SetsValue ()
+		public void Point_SetsValue ()
 		{
 		{
 			var point = new Point () {
 			var point = new Point () {
 				X = 0,
 				X = 0,

+ 1 - 1
UnitTests/PosTests.cs

@@ -10,7 +10,7 @@ using Xunit;
 // Alais Console to MockConsole so we don't accidentally use Console
 // Alais Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-namespace Terminal.Gui {
+namespace Terminal.Gui.Core {
 	public class PosTests {
 	public class PosTests {
 		[Fact]
 		[Fact]
 		public void New_Works ()
 		public void New_Works ()

+ 2 - 2
UnitTests/RectTests.cs

@@ -1,7 +1,7 @@
 using System;
 using System;
 using Xunit;
 using Xunit;
 
 
-namespace Terminal.Gui {
+namespace Terminal.Gui.Types {
 	public class RectTests {
 	public class RectTests {
 		[Fact]
 		[Fact]
 		public void Rect_New ()
 		public void Rect_New ()
@@ -33,7 +33,7 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		public void Rect__SetsValue ()
+		public void Rect_SetsValue ()
 		{
 		{
 			var rect = new Rect () {
 			var rect = new Rect () {
 				X = 0,
 				X = 0,

+ 1 - 1
UnitTests/ResponderTests.cs

@@ -7,7 +7,7 @@ using Xunit;
 // Alais Console to MockConsole so we don't accidentally use Console
 // Alais Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-namespace Terminal.Gui {
+namespace Terminal.Gui.Core {
 	public class ResponderTests {
 	public class ResponderTests {
 		[Fact]
 		[Fact]
 		public void New_Initializes ()
 		public void New_Initializes ()

+ 6 - 2
UnitTests/ScenarioTests.cs

@@ -43,10 +43,14 @@ namespace Terminal.Gui {
 			Assert.NotEmpty (scenarioClasses);
 			Assert.NotEmpty (scenarioClasses);
 
 
 			foreach (var scenarioClass in scenarioClasses) {
 			foreach (var scenarioClass in scenarioClasses) {
+
 				// Setup some fake keypresses 
 				// Setup some fake keypresses 
 				// Passing empty string will cause just a ctrl-q to be fired
 				// Passing empty string will cause just a ctrl-q to be fired
 				Console.MockKeyPresses.Clear ();
 				Console.MockKeyPresses.Clear ();
 				int stackSize = CreateInput ("");
 				int stackSize = CreateInput ("");
+
+				Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+
 				int iterations = 0;
 				int iterations = 0;
 				Application.Iteration = () => {
 				Application.Iteration = () => {
 					iterations++;
 					iterations++;
@@ -55,7 +59,6 @@ namespace Terminal.Gui {
 						Application.RequestStop ();
 						Application.RequestStop ();
 					}
 					}
 				};
 				};
-				Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
 
 
 				var ms = 1000;
 				var ms = 1000;
 				var abortCount = 0;
 				var abortCount = 0;
@@ -99,6 +102,8 @@ namespace Terminal.Gui {
 			// Passing empty string will cause just a ctrl-q to be fired
 			// Passing empty string will cause just a ctrl-q to be fired
 			int stackSize = CreateInput ("");
 			int stackSize = CreateInput ("");
 
 
+			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
+
 			int iterations = 0;
 			int iterations = 0;
 			Application.Iteration = () => {
 			Application.Iteration = () => {
 				iterations++;
 				iterations++;
@@ -107,7 +112,6 @@ namespace Terminal.Gui {
 					Application.RequestStop ();
 					Application.RequestStop ();
 				}
 				}
 			};
 			};
-			Application.Init (new FakeDriver (), new FakeMainLoop (() => FakeConsole.ReadKey (true)));
 
 
 			var ms = 1000;
 			var ms = 1000;
 			var abortCount = 0;
 			var abortCount = 0;

+ 1 - 1
UnitTests/ScrollBarViewTests.cs

@@ -1,7 +1,7 @@
 using System;
 using System;
 using Xunit;
 using Xunit;
 
 
-namespace Terminal.Gui {
+namespace Terminal.Gui.Views {
 	public class ScrollBarViewTests {
 	public class ScrollBarViewTests {
 		public class HostView : View {
 		public class HostView : View {
 			public int Top { get; set; }
 			public int Top { get; set; }

+ 2 - 2
UnitTests/SizeTests.cs

@@ -1,7 +1,7 @@
 using System;
 using System;
 using Xunit;
 using Xunit;
 
 
-namespace Terminal.Gui {
+namespace Terminal.Gui.Types {
 	public class SizeTests {
 	public class SizeTests {
 		[Fact]
 		[Fact]
 		public void Size_New ()
 		public void Size_New ()
@@ -30,7 +30,7 @@ namespace Terminal.Gui {
 		}
 		}
 
 
 		[Fact]
 		[Fact]
-		public void Size__SetsValue ()
+		public void Size_SetsValue ()
 		{
 		{
 			var size = new Size () {
 			var size = new Size () {
 				Width = 0,
 				Width = 0,

+ 1 - 1
UnitTests/TabViewTests.cs

@@ -7,7 +7,7 @@ using Terminal.Gui;
 using Xunit;
 using Xunit;
 using System.Globalization;
 using System.Globalization;
 
 
-namespace UnitTests {
+namespace Terminal.Gui.Views {
 	public class TabViewTests {
 	public class TabViewTests {
 		private TabView GetTabView ()
 		private TabView GetTabView ()
 		{
 		{

+ 1 - 1
UnitTests/TableViewTests.cs

@@ -7,7 +7,7 @@ using Terminal.Gui;
 using Xunit;
 using Xunit;
 using System.Globalization;
 using System.Globalization;
 
 
-namespace UnitTests {
+namespace Terminal.Gui.Views {
 	public class TableViewTests 
 	public class TableViewTests 
 	{
 	{
 
 

+ 1 - 1
UnitTests/TextFieldTests.cs

@@ -1,6 +1,6 @@
 using Xunit;
 using Xunit;
 
 
-namespace Terminal.Gui {
+namespace Terminal.Gui.Views {
 	public class TextFieldTests {
 	public class TextFieldTests {
 		private TextField _textField;
 		private TextField _textField;
 
 

+ 1 - 1
UnitTests/TextFormatterTests.cs

@@ -10,7 +10,7 @@ using Xunit;
 // Alias Console to MockConsole so we don't accidentally use Console
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-namespace Terminal.Gui {
+namespace Terminal.Gui.Core {
 	public class TextFormatterTests {
 	public class TextFormatterTests {
 
 
 		[Fact]
 		[Fact]

+ 1 - 1
UnitTests/TextViewTests.cs

@@ -1,7 +1,7 @@
 using System;
 using System;
 using Xunit;
 using Xunit;
 
 
-namespace Terminal.Gui {
+namespace Terminal.Gui.Views {
 	public class TextViewTests {
 	public class TextViewTests {
 		private TextView _textView;
 		private TextView _textView;
 
 

+ 1 - 1
UnitTests/TreeViewTests.cs

@@ -6,7 +6,7 @@ using System.Threading.Tasks;
 using Terminal.Gui;
 using Terminal.Gui;
 using Xunit;
 using Xunit;
 
 
-namespace UnitTests {
+namespace Terminal.Gui.Views {
 	public class TreeViewTests {
 	public class TreeViewTests {
 		#region Test Setup Methods
 		#region Test Setup Methods
 		class Factory {
 		class Factory {

+ 24 - 1
UnitTests/UnitTests.csproj

@@ -1,8 +1,9 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
 
 
   <PropertyGroup>
   <PropertyGroup>
     <TargetFramework>net5.0</TargetFramework>
     <TargetFramework>net5.0</TargetFramework>
     <IsPackable>false</IsPackable>
     <IsPackable>false</IsPackable>
+    <UseDataCollector />
   </PropertyGroup>
   </PropertyGroup>
 
 
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
@@ -15,6 +16,7 @@
 
 
   <ItemGroup>
   <ItemGroup>
     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
     <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
+    <PackageReference Include="ReportGenerator" Version="4.8.7" />
     <PackageReference Include="System.Collections" Version="4.3.0" />
     <PackageReference Include="System.Collections" Version="4.3.0" />
     <PackageReference Include="xunit" Version="2.4.1" />
     <PackageReference Include="xunit" Version="2.4.1" />
     <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
     <PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
@@ -32,4 +34,25 @@
     <ProjectReference Include="..\UICatalog\UICatalog.csproj" />
     <ProjectReference Include="..\UICatalog\UICatalog.csproj" />
   </ItemGroup>
   </ItemGroup>
 
 
+  <PropertyGroup Label="FineCodeCoverage">
+    <Enabled>
+      True
+    </Enabled>
+    <Exclude>
+      [UICatalog]*
+    </Exclude>
+    <Include>
+    </Include>
+    <ExcludeByFile>
+      <!--**/Migrations/*
+      **/Hacks/*.cs-->
+    </ExcludeByFile>
+    <ExcludeByAttribute>
+      <!--MyCustomExcludeFromCodeCoverage-->
+    </ExcludeByAttribute>
+    <IncludeTestAssembly>
+      False
+    </IncludeTestAssembly>
+  </PropertyGroup>
+  
 </Project>
 </Project>

+ 4 - 4
UnitTests/ViewTests.cs

@@ -9,7 +9,7 @@ using Xunit;
 // Alias Console to MockConsole so we don't accidentally use Console
 // Alias Console to MockConsole so we don't accidentally use Console
 using Console = Terminal.Gui.FakeConsole;
 using Console = Terminal.Gui.FakeConsole;
 
 
-namespace Terminal.Gui {
+namespace Terminal.Gui.Views {
 	public class ViewTests {
 	public class ViewTests {
 		[Fact]
 		[Fact]
 		public void New_Initializes ()
 		public void New_Initializes ()
@@ -944,10 +944,10 @@ namespace Terminal.Gui {
 				if (count1 == 5) {
 				if (count1 == 5) {
 					log1 = true;
 					log1 = true;
 				}
 				}
-				if (count1 > 13 && count < 15) {
+				if (count1 == 14 && count2 == 10 && count == 15) { // count2 is already stopped
 					fromTopStillKnowFirstIsRunning = true;
 					fromTopStillKnowFirstIsRunning = true;
 				}
 				}
-				if (count2 > 6 && count2 < 8) {
+				if (count1 == 7 && count2 == 7 && count == 8) {
 					fromTopStillKnowSecondIsRunning = true;
 					fromTopStillKnowSecondIsRunning = true;
 				}
 				}
 				if (count == 30) {
 				if (count == 30) {
@@ -981,7 +981,7 @@ namespace Terminal.Gui {
 					if (count2 == 5) {
 					if (count2 == 5) {
 						log2 = true;
 						log2 = true;
 					}
 					}
-					if (count2 > 3 && count2 < 5) {
+					if (count2 == 4 && count1 == 5 && count == 5) {
 						fromFirstStillKnowSecondIsRunning = true;
 						fromFirstStillKnowSecondIsRunning = true;
 					}
 					}
 					if (count1 == 20) {
 					if (count1 == 20) {

+ 23 - 0
UnitTests/coverlet.runsettings

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<RunSettings>
+  <DataCollectionRunSettings>
+    <DataCollectors>
+      <DataCollector friendlyName="XPlat code coverage">
+        <Configuration>
+          <Format>opencover</Format>          
+          <Exclude>[UnitTests]*,[UICatalog]*,[coverlet.*.tests?]*,[*]Coverlet.Core*</Exclude> <!-- [Assembly-Filter]Type-Filter -->
+          <Include></Include> <!-- [Assembly-Filter]Type-Filter -->
+          <ExcludeByAttribute></ExcludeByAttribute>
+          <ExcludeByFile></ExcludeByFile> <!-- Globbing filter -->
+          <IncludeDirectory></IncludeDirectory>
+          <SingleHit>false</SingleHit>
+          <UseSourceLink>true</UseSourceLink>
+          <IncludeTestAssembly>true</IncludeTestAssembly>
+          <SkipAutoProps>true</SkipAutoProps>
+          <DeterministicReport>false</DeterministicReport>
+          <ResultsDirectory>TestResults/</ResultsDirectory>
+        </Configuration>
+      </DataCollector>
+    </DataCollectors>
+  </DataCollectionRunSettings>
+</RunSettings>