SEBWIN-380: Started implementing unit tests for browser component handlers.
This commit is contained in:
		
							parent
							
								
									5eff32a7bc
								
							
						
					
					
						commit
						d3ce3ee9e1
					
				
					 8 changed files with 738 additions and 3 deletions
				
			
		|  | @ -29,15 +29,15 @@ namespace SafeExamBrowser.Browser.UnitTests.Handlers | ||||||
| 		{ | 		{ | ||||||
| 			var menu = new Mock<IMenuModel>(); | 			var menu = new Mock<IMenuModel>(); | ||||||
| 
 | 
 | ||||||
| 			sut.OnBeforeContextMenu(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), Mock.Of<IFrame>(), Mock.Of<IContextMenuParams>(), menu.Object); | 			sut.OnBeforeContextMenu(default(IWebBrowser), default(IBrowser), default(IFrame), default(IContextMenuParams), menu.Object); | ||||||
| 			menu.Verify(m => m.Clear(), Times.Once); | 			menu.Verify(m => m.Clear(), Times.Once); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		[TestMethod] | 		[TestMethod] | ||||||
| 		public void MustBlockContextMenu() | 		public void MustBlockContextMenu() | ||||||
| 		{ | 		{ | ||||||
| 			var command = sut.OnContextMenuCommand(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), Mock.Of<IFrame>(), Mock.Of<IContextMenuParams>(), default(CefMenuCommand), default(CefEventFlags)); | 			var command = sut.OnContextMenuCommand(default(IWebBrowser), default(IBrowser), default(IFrame), default(IContextMenuParams), default(CefMenuCommand), default(CefEventFlags)); | ||||||
| 			var run = sut.RunContextMenu(Mock.Of<IWebBrowser>(), Mock.Of<IBrowser>(), Mock.Of<IFrame>(), Mock.Of<IContextMenuParams>(), Mock.Of<IMenuModel>(), Mock.Of<IRunContextMenuCallback>()); | 			var run = sut.RunContextMenu(default(IWebBrowser), default(IBrowser), default(IFrame), default(IContextMenuParams), default(IMenuModel), default(IRunContextMenuCallback)); | ||||||
| 
 | 
 | ||||||
| 			Assert.IsFalse(command); | 			Assert.IsFalse(command); | ||||||
| 			Assert.IsFalse(run); | 			Assert.IsFalse(run); | ||||||
|  |  | ||||||
							
								
								
									
										106
									
								
								SafeExamBrowser.Browser.UnitTests/Handlers/DialogHandlerTests.cs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								SafeExamBrowser.Browser.UnitTests/Handlers/DialogHandlerTests.cs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,106 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  *  | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | using System.Collections.Generic; | ||||||
|  | using System.Threading; | ||||||
|  | using CefSharp; | ||||||
|  | using Microsoft.VisualStudio.TestTools.UnitTesting; | ||||||
|  | using Moq; | ||||||
|  | using SafeExamBrowser.Browser.Events; | ||||||
|  | using SafeExamBrowser.Browser.Handlers; | ||||||
|  | using SafeExamBrowser.UserInterface.Contracts.FileSystemDialog; | ||||||
|  | 
 | ||||||
|  | namespace SafeExamBrowser.Browser.UnitTests.Handlers | ||||||
|  | { | ||||||
|  | 	[TestClass] | ||||||
|  | 	public class DialogHandlerTests | ||||||
|  | 	{ | ||||||
|  | 		private DialogHandler sut; | ||||||
|  | 
 | ||||||
|  | 		[TestInitialize] | ||||||
|  | 		public void Initialize() | ||||||
|  | 		{ | ||||||
|  | 			sut = new DialogHandler(); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void MustCorrectlyCancelDialog() | ||||||
|  | 		{ | ||||||
|  | 			RequestDialog(default(CefFileDialogMode), false); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void MustCorrectlyRequestOpenFileDialog() | ||||||
|  | 		{ | ||||||
|  | 			var args = RequestDialog(CefFileDialogMode.Open); | ||||||
|  | 
 | ||||||
|  | 			Assert.AreEqual(FileSystemElement.File, args.Element); | ||||||
|  | 			Assert.AreEqual(FileSystemOperation.Open, args.Operation); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void MustCorrectlyRequestOpenFolderDialog() | ||||||
|  | 		{ | ||||||
|  | 			var args = RequestDialog(CefFileDialogMode.OpenFolder); | ||||||
|  | 
 | ||||||
|  | 			Assert.AreEqual(FileSystemElement.Folder, args.Element); | ||||||
|  | 			Assert.AreEqual(FileSystemOperation.Open, args.Operation); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void MustCorrectlyRequestSaveFileDialog() | ||||||
|  | 		{ | ||||||
|  | 			var args = RequestDialog(CefFileDialogMode.Save); | ||||||
|  | 
 | ||||||
|  | 			Assert.AreEqual(FileSystemElement.File, args.Element); | ||||||
|  | 			Assert.AreEqual(FileSystemOperation.Save, args.Operation); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		private DialogRequestedEventArgs RequestDialog(CefFileDialogMode mode, bool confirm = true) | ||||||
|  | 		{ | ||||||
|  | 			var args = default(DialogRequestedEventArgs); | ||||||
|  | 			var callback = new Mock<IFileDialogCallback>(); | ||||||
|  | 			var title = "Some random dialog title"; | ||||||
|  | 			var initialPath = @"C:\Some\Random\Path"; | ||||||
|  | 			var sync = new AutoResetEvent(false); | ||||||
|  | 			var threadId = default(int); | ||||||
|  | 
 | ||||||
|  | 			callback.Setup(c => c.Cancel()).Callback(() => sync.Set()); | ||||||
|  | 			callback.Setup(c => c.Continue(It.IsAny<int>(), It.IsAny<List<string>>())).Callback(() => sync.Set()); | ||||||
|  | 			sut.DialogRequested += (a) => | ||||||
|  | 			{ | ||||||
|  | 				args = a; | ||||||
|  | 				args.Success = confirm; | ||||||
|  | 				args.FullPath = @"D:\Some\Other\File\Path.txt"; | ||||||
|  | 				threadId = Thread.CurrentThread.ManagedThreadId; | ||||||
|  | 			}; | ||||||
|  | 
 | ||||||
|  | 			var status = sut.OnFileDialog(default(IWebBrowser), default(IBrowser), mode, default(CefFileDialogFlags), title, initialPath, default(List<string>), default(int), callback.Object); | ||||||
|  | 
 | ||||||
|  | 			sync.WaitOne(); | ||||||
|  | 
 | ||||||
|  | 			if (confirm) | ||||||
|  | 			{ | ||||||
|  | 				callback.Verify(c => c.Continue(It.IsAny<int>(), It.IsAny<List<string>>()), Times.Once); | ||||||
|  | 				callback.Verify(c => c.Cancel(), Times.Never); | ||||||
|  | 			} | ||||||
|  | 			else | ||||||
|  | 			{ | ||||||
|  | 				callback.Verify(c => c.Continue(It.IsAny<int>(), It.IsAny<List<string>>()), Times.Never); | ||||||
|  | 				callback.Verify(c => c.Cancel(), Times.Once); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			Assert.IsTrue(status); | ||||||
|  | 			Assert.AreEqual(initialPath, args.InitialPath); | ||||||
|  | 			Assert.AreEqual(title, args.Title); | ||||||
|  | 			Assert.AreNotEqual(threadId, Thread.CurrentThread.ManagedThreadId); | ||||||
|  | 
 | ||||||
|  | 			return args; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -0,0 +1,73 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  *  | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | using System.Collections.Generic; | ||||||
|  | using CefSharp; | ||||||
|  | using CefSharp.Structs; | ||||||
|  | using Microsoft.VisualStudio.TestTools.UnitTesting; | ||||||
|  | using SafeExamBrowser.Browser.Handlers; | ||||||
|  | 
 | ||||||
|  | namespace SafeExamBrowser.Browser.UnitTests.Handlers | ||||||
|  | { | ||||||
|  | 	[TestClass] | ||||||
|  | 	public class DisplayHandlerTests | ||||||
|  | 	{ | ||||||
|  | 		private DisplayHandler sut; | ||||||
|  | 
 | ||||||
|  | 		[TestInitialize] | ||||||
|  | 		public void Initialize() | ||||||
|  | 		{ | ||||||
|  | 			sut = new DisplayHandler(); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void MustUseDefaultHandling() | ||||||
|  | 		{ | ||||||
|  | 			var text = default(string); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsFalse(sut.OnAutoResize(default(IWebBrowser), default(IBrowser), default(Size))); | ||||||
|  | 			Assert.IsFalse(sut.OnConsoleMessage(default(IWebBrowser), default(ConsoleMessageEventArgs))); | ||||||
|  | 			Assert.IsFalse(sut.OnTooltipChanged(default(IWebBrowser), ref text)); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void MustHandleFaviconChange() | ||||||
|  | 		{ | ||||||
|  | 			var newUrl = "www.someurl.org/favicon.ico"; | ||||||
|  | 			var url = default(string); | ||||||
|  | 			var called = false; | ||||||
|  | 
 | ||||||
|  | 			sut.FaviconChanged += (u) => | ||||||
|  | 			{ | ||||||
|  | 				called = true; | ||||||
|  | 				url = u; | ||||||
|  | 			}; | ||||||
|  | 			sut.OnFaviconUrlChange(default(IWebBrowser), default(IBrowser), new List<string>()); | ||||||
|  | 
 | ||||||
|  | 			Assert.AreEqual(default(string), url); | ||||||
|  | 			Assert.IsFalse(called); | ||||||
|  | 
 | ||||||
|  | 			sut.OnFaviconUrlChange(default(IWebBrowser), default(IBrowser), new List<string> { newUrl }); | ||||||
|  | 
 | ||||||
|  | 			Assert.AreEqual(newUrl, url); | ||||||
|  | 			Assert.IsTrue(called); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void MustHandleProgressChange() | ||||||
|  | 		{ | ||||||
|  | 			var expected = 0.123456; | ||||||
|  | 			var actual = default(double); | ||||||
|  | 
 | ||||||
|  | 			sut.ProgressChanged += (p) => actual = p; | ||||||
|  | 			sut.OnLoadingProgressChange(default(IWebBrowser), default(IBrowser), expected); | ||||||
|  | 
 | ||||||
|  | 			Assert.AreEqual(expected, actual); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -0,0 +1,308 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  *  | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | using System; | ||||||
|  | using System.IO; | ||||||
|  | using System.Threading; | ||||||
|  | using CefSharp; | ||||||
|  | using Microsoft.VisualStudio.TestTools.UnitTesting; | ||||||
|  | using Moq; | ||||||
|  | using SafeExamBrowser.Browser.Contracts.Events; | ||||||
|  | using SafeExamBrowser.Browser.Handlers; | ||||||
|  | using SafeExamBrowser.Configuration.Contracts; | ||||||
|  | using SafeExamBrowser.Logging.Contracts; | ||||||
|  | using SafeExamBrowser.UserInterface.Contracts.Browser.Data; | ||||||
|  | using BrowserSettings = SafeExamBrowser.Settings.Browser.BrowserSettings; | ||||||
|  | 
 | ||||||
|  | namespace SafeExamBrowser.Browser.UnitTests.Handlers | ||||||
|  | { | ||||||
|  | 	[TestClass] | ||||||
|  | 	public class DownloadHandlerTests | ||||||
|  | 	{ | ||||||
|  | 		private AppConfig appConfig; | ||||||
|  | 		private BrowserSettings settings; | ||||||
|  | 		private Mock<ILogger> logger; | ||||||
|  | 		private DownloadHandler sut; | ||||||
|  | 
 | ||||||
|  | 		[TestInitialize] | ||||||
|  | 		public void Initialize() | ||||||
|  | 		{ | ||||||
|  | 			appConfig = new AppConfig(); | ||||||
|  | 			settings = new BrowserSettings(); | ||||||
|  | 			logger = new Mock<ILogger>(); | ||||||
|  | 
 | ||||||
|  | 			sut = new DownloadHandler(appConfig, settings, logger.Object); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void MustCorrectlyHandleConfigurationByFileExtension() | ||||||
|  | 		{ | ||||||
|  | 			var item = new DownloadItem | ||||||
|  | 			{ | ||||||
|  | 				SuggestedFileName = "File.seb", | ||||||
|  | 				Url = "https://somehost.org/some-path" | ||||||
|  | 			}; | ||||||
|  | 
 | ||||||
|  | 			RequestConfigurationDownload(item); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void MustCorrectlyHandleConfigurationByUrlExtension() | ||||||
|  | 		{ | ||||||
|  | 			var item = new DownloadItem | ||||||
|  | 			{ | ||||||
|  | 				SuggestedFileName = "Abc.xyz", | ||||||
|  | 				Url = "https://somehost.org/some-path-to/file.seb" | ||||||
|  | 			}; | ||||||
|  | 
 | ||||||
|  | 			RequestConfigurationDownload(item); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void MustCorrectlyHandleConfigurationByMimeType() | ||||||
|  | 		{ | ||||||
|  | 			appConfig.ConfigurationFileMimeType = "some/mime-type"; | ||||||
|  | 
 | ||||||
|  | 			var item = new DownloadItem | ||||||
|  | 			{ | ||||||
|  | 				MimeType = appConfig.ConfigurationFileMimeType, | ||||||
|  | 				SuggestedFileName = "Abc.xyz", | ||||||
|  | 				Url = "https://somehost.org/some-path" | ||||||
|  | 			}; | ||||||
|  | 
 | ||||||
|  | 			RequestConfigurationDownload(item); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void MustCorrectlyHandleDeniedConfigurationFileDownload() | ||||||
|  | 		{ | ||||||
|  | 			var args = default(DownloadEventArgs); | ||||||
|  | 			var callback = new Mock<IBeforeDownloadCallback>(); | ||||||
|  | 			var failed = false; | ||||||
|  | 			var fileName = default(string); | ||||||
|  | 			var item = new DownloadItem | ||||||
|  | 			{ | ||||||
|  | 				SuggestedFileName = "File.seb", | ||||||
|  | 				Url = "https://somehost.org/some-path" | ||||||
|  | 			}; | ||||||
|  | 			var sync = new AutoResetEvent(false); | ||||||
|  | 			var threadId = default(int); | ||||||
|  | 
 | ||||||
|  | 			settings.AllowDownloads = false; | ||||||
|  | 			settings.AllowConfigurationDownloads = true; | ||||||
|  | 			sut.ConfigurationDownloadRequested += (f, a) => | ||||||
|  | 			{ | ||||||
|  | 				args = a; | ||||||
|  | 				args.AllowDownload = false; | ||||||
|  | 				fileName = f; | ||||||
|  | 				threadId = Thread.CurrentThread.ManagedThreadId; | ||||||
|  | 				sync.Set(); | ||||||
|  | 			}; | ||||||
|  | 			sut.DownloadUpdated += (state) => failed = true; | ||||||
|  | 
 | ||||||
|  | 			sut.OnBeforeDownload(default(IWebBrowser), default(IBrowser), item, callback.Object); | ||||||
|  | 			sync.WaitOne(); | ||||||
|  | 
 | ||||||
|  | 			callback.VerifyNoOtherCalls(); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsFalse(failed); | ||||||
|  | 			Assert.IsFalse(args.AllowDownload); | ||||||
|  | 			Assert.AreEqual(item.SuggestedFileName, fileName); | ||||||
|  | 			Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, threadId); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void MustCorrectlyHandleFileDownload() | ||||||
|  | 		{ | ||||||
|  | 			var callback = new Mock<IBeforeDownloadCallback>(); | ||||||
|  | 			var downloadPath = default(string); | ||||||
|  | 			var failed = false; | ||||||
|  | 			var item = new DownloadItem | ||||||
|  | 			{ | ||||||
|  | 				MimeType = "application/something", | ||||||
|  | 				SuggestedFileName = "File.txt", | ||||||
|  | 				Url = "https://somehost.org/somefile.abc" | ||||||
|  | 			}; | ||||||
|  | 			var sync = new AutoResetEvent(false); | ||||||
|  | 			var threadId = default(int); | ||||||
|  | 
 | ||||||
|  | 			callback.Setup(c => c.Continue(It.IsAny<string>(), It.IsAny<bool>())).Callback<string, bool>((f, s) => | ||||||
|  | 			{ | ||||||
|  | 				downloadPath = f; | ||||||
|  | 				threadId = Thread.CurrentThread.ManagedThreadId; | ||||||
|  | 				sync.Set(); | ||||||
|  | 			}); | ||||||
|  | 			settings.AllowDownloads = true; | ||||||
|  | 			settings.AllowConfigurationDownloads = false; | ||||||
|  | 			sut.ConfigurationDownloadRequested += (f, a) => failed = true; | ||||||
|  | 			sut.DownloadUpdated += (state) => failed = true; | ||||||
|  | 
 | ||||||
|  | 			sut.OnBeforeDownload(default(IWebBrowser), default(IBrowser), item, callback.Object); | ||||||
|  | 			sync.WaitOne(); | ||||||
|  | 
 | ||||||
|  | 			callback.Verify(c => c.Continue(It.Is<string>(p => p.Equals(downloadPath)), false), Times.Once); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsFalse(failed); | ||||||
|  | 			Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, threadId); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void MustCorrectlyHandleFileDownloadWithCustomDirectory() | ||||||
|  | 		{ | ||||||
|  | 			var callback = new Mock<IBeforeDownloadCallback>(); | ||||||
|  | 			var failed = false; | ||||||
|  | 			var item = new DownloadItem | ||||||
|  | 			{ | ||||||
|  | 				MimeType = "application/something", | ||||||
|  | 				SuggestedFileName = "File.txt", | ||||||
|  | 				Url = "https://somehost.org/somefile.abc" | ||||||
|  | 			}; | ||||||
|  | 			var sync = new AutoResetEvent(false); | ||||||
|  | 			var threadId = default(int); | ||||||
|  | 
 | ||||||
|  | 			callback.Setup(c => c.Continue(It.IsAny<string>(), It.IsAny<bool>())).Callback(() => | ||||||
|  | 			{ | ||||||
|  | 				threadId = Thread.CurrentThread.ManagedThreadId; | ||||||
|  | 				sync.Set(); | ||||||
|  | 			}); | ||||||
|  | 			settings.AllowDownloads = true; | ||||||
|  | 			settings.AllowConfigurationDownloads = false; | ||||||
|  | 			settings.AllowCustomDownloadLocation = true; | ||||||
|  | 			settings.DownloadDirectory = @"%APPDATA%\Downloads"; | ||||||
|  | 			sut.ConfigurationDownloadRequested += (f, a) => failed = true; | ||||||
|  | 			sut.DownloadUpdated += (state) => failed = true; | ||||||
|  | 
 | ||||||
|  | 			sut.OnBeforeDownload(default(IWebBrowser), default(IBrowser), item, callback.Object); | ||||||
|  | 			sync.WaitOne(); | ||||||
|  | 
 | ||||||
|  | 			var downloadPath = Path.Combine(Environment.ExpandEnvironmentVariables(settings.DownloadDirectory), item.SuggestedFileName); | ||||||
|  | 
 | ||||||
|  | 			callback.Verify(c => c.Continue(It.Is<string>(p => p.Equals(downloadPath)), true), Times.Once); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsFalse(failed); | ||||||
|  | 			Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, threadId); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void MustDoNothingIfDownloadsNotAllowed() | ||||||
|  | 		{ | ||||||
|  | 			var callback = new Mock<IBeforeDownloadCallback>(); | ||||||
|  | 			var fail = false; | ||||||
|  | 			var item = new DownloadItem | ||||||
|  | 			{ | ||||||
|  | 				SuggestedFileName = "File.txt", | ||||||
|  | 				Url = "https://somehost.org/somefile.abc" | ||||||
|  | 			}; | ||||||
|  | 
 | ||||||
|  | 			settings.AllowDownloads = false; | ||||||
|  | 			settings.AllowConfigurationDownloads = false; | ||||||
|  | 			sut.ConfigurationDownloadRequested += (file, args) => fail = true; | ||||||
|  | 			sut.DownloadUpdated += (state) => fail = true; | ||||||
|  | 
 | ||||||
|  | 			sut.OnBeforeDownload(default(IWebBrowser), default(IBrowser), item, callback.Object); | ||||||
|  | 
 | ||||||
|  | 			callback.VerifyNoOtherCalls(); | ||||||
|  | 			Assert.IsFalse(fail); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void MustUpdateDownloadProgress() | ||||||
|  | 		{ | ||||||
|  | 			var callback = new Mock<IBeforeDownloadCallback>(); | ||||||
|  | 			var failed = false; | ||||||
|  | 			var item = new DownloadItem | ||||||
|  | 			{ | ||||||
|  | 				MimeType = "application/something", | ||||||
|  | 				SuggestedFileName = "File.txt", | ||||||
|  | 				Url = "https://somehost.org/somefile.abc" | ||||||
|  | 			}; | ||||||
|  | 			var state = default(DownloadItemState); | ||||||
|  | 			var sync = new AutoResetEvent(false); | ||||||
|  | 			var threadId = default(int); | ||||||
|  | 
 | ||||||
|  | 			callback.Setup(c => c.Continue(It.IsAny<string>(), It.IsAny<bool>())).Callback(() => sync.Set()); | ||||||
|  | 			settings.AllowDownloads = true; | ||||||
|  | 			settings.AllowConfigurationDownloads = false; | ||||||
|  | 			sut.ConfigurationDownloadRequested += (f, a) => failed = true; | ||||||
|  | 
 | ||||||
|  | 			sut.OnBeforeDownload(default(IWebBrowser), default(IBrowser), item, callback.Object); | ||||||
|  | 			sync.WaitOne(); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsFalse(failed); | ||||||
|  | 
 | ||||||
|  | 			sut.DownloadUpdated += (s) => | ||||||
|  | 			{ | ||||||
|  | 				state = s; | ||||||
|  | 				threadId = Thread.CurrentThread.ManagedThreadId; | ||||||
|  | 				sync.Set(); | ||||||
|  | 			}; | ||||||
|  | 
 | ||||||
|  | 			item.PercentComplete = 10; | ||||||
|  | 			sut.OnDownloadUpdated(default(IWebBrowser), default(IBrowser), item, default(IDownloadItemCallback)); | ||||||
|  | 			sync.WaitOne(); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsFalse(state.IsCancelled); | ||||||
|  | 			Assert.IsFalse(state.IsComplete); | ||||||
|  | 			Assert.AreEqual(0.1, state.Completion); | ||||||
|  | 			Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, threadId); | ||||||
|  | 
 | ||||||
|  | 			item.PercentComplete = 20; | ||||||
|  | 			sut.OnDownloadUpdated(default(IWebBrowser), default(IBrowser), item, default(IDownloadItemCallback)); | ||||||
|  | 			sync.WaitOne(); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsFalse(state.IsCancelled); | ||||||
|  | 			Assert.IsFalse(state.IsComplete); | ||||||
|  | 			Assert.AreEqual(0.2, state.Completion); | ||||||
|  | 			Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, threadId); | ||||||
|  | 
 | ||||||
|  | 			item.PercentComplete = 50; | ||||||
|  | 			item.IsCancelled = true; | ||||||
|  | 			sut.OnDownloadUpdated(default(IWebBrowser), default(IBrowser), item, default(IDownloadItemCallback)); | ||||||
|  | 			sync.WaitOne(); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsFalse(failed); | ||||||
|  | 			Assert.IsTrue(state.IsCancelled); | ||||||
|  | 			Assert.IsFalse(state.IsComplete); | ||||||
|  | 			Assert.AreEqual(0.5, state.Completion); | ||||||
|  | 			Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, threadId); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		private void RequestConfigurationDownload(DownloadItem item) | ||||||
|  | 		{ | ||||||
|  | 			var args = default(DownloadEventArgs); | ||||||
|  | 			var callback = new Mock<IBeforeDownloadCallback>(); | ||||||
|  | 			var failed = false; | ||||||
|  | 			var fileName = default(string); | ||||||
|  | 			var sync = new AutoResetEvent(false); | ||||||
|  | 			var threadId = default(int); | ||||||
|  | 
 | ||||||
|  | 			callback.Setup(c => c.Continue(It.IsAny<string>(), It.IsAny<bool>())).Callback(() => sync.Set()); | ||||||
|  | 			settings.AllowDownloads = false; | ||||||
|  | 			settings.AllowConfigurationDownloads = true; | ||||||
|  | 			sut.ConfigurationDownloadRequested += (f, a) => | ||||||
|  | 			{ | ||||||
|  | 				args = a; | ||||||
|  | 				args.AllowDownload = true; | ||||||
|  | 				args.DownloadPath = @"C:\Downloads\File.seb"; | ||||||
|  | 				fileName = f; | ||||||
|  | 				threadId = Thread.CurrentThread.ManagedThreadId; | ||||||
|  | 			}; | ||||||
|  | 			sut.DownloadUpdated += (state) => failed = true; | ||||||
|  | 
 | ||||||
|  | 			sut.OnBeforeDownload(default(IWebBrowser), default(IBrowser), item, callback.Object); | ||||||
|  | 			sync.WaitOne(); | ||||||
|  | 
 | ||||||
|  | 			callback.Verify(c => c.Continue(It.Is<string>(p => p.Equals(args.DownloadPath)), false), Times.Once); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsFalse(failed); | ||||||
|  | 			Assert.IsTrue(args.AllowDownload); | ||||||
|  | 			Assert.AreEqual(item.SuggestedFileName, fileName); | ||||||
|  | 			Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, threadId); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -0,0 +1,128 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  *  | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | using System.Windows.Forms; | ||||||
|  | using CefSharp; | ||||||
|  | using Microsoft.VisualStudio.TestTools.UnitTesting; | ||||||
|  | using SafeExamBrowser.Browser.Handlers; | ||||||
|  | 
 | ||||||
|  | namespace SafeExamBrowser.Browser.UnitTests.Handlers | ||||||
|  | { | ||||||
|  | 	[TestClass] | ||||||
|  | 	public class KeyboardHandlerTests | ||||||
|  | 	{ | ||||||
|  | 		private KeyboardHandler sut; | ||||||
|  | 
 | ||||||
|  | 		[TestInitialize] | ||||||
|  | 		public void Initialize() | ||||||
|  | 		{ | ||||||
|  | 			sut = new KeyboardHandler(); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void MustDetectReload() | ||||||
|  | 		{ | ||||||
|  | 			var isShortcut = default(bool); | ||||||
|  | 			var reloadRequested = false; | ||||||
|  | 
 | ||||||
|  | 			sut.ReloadRequested += () => reloadRequested = true; | ||||||
|  | 
 | ||||||
|  | 			var handled = sut.OnPreKeyEvent(default(IWebBrowser), default(IBrowser), KeyType.KeyUp, (int)Keys.F5, default(int), default(CefEventFlags), default(bool), ref isShortcut); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsTrue(reloadRequested); | ||||||
|  | 			Assert.IsTrue(handled); | ||||||
|  | 
 | ||||||
|  | 			reloadRequested = false; | ||||||
|  | 			handled = sut.OnPreKeyEvent(default(IWebBrowser), default(IBrowser), default(KeyType), default(int), default(int), default(CefEventFlags), default(bool), ref isShortcut); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsFalse(reloadRequested); | ||||||
|  | 			Assert.IsFalse(handled); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void MustDetectZoomInCommand() | ||||||
|  | 		{ | ||||||
|  | 			var zoomIn = false; | ||||||
|  | 			var zoomOut = false; | ||||||
|  | 			var zoomReset = false; | ||||||
|  | 
 | ||||||
|  | 			sut.ZoomInRequested += () => zoomIn = true; | ||||||
|  | 			sut.ZoomOutRequested += () => zoomOut = true; | ||||||
|  | 			sut.ZoomResetRequested += () => zoomReset = true; | ||||||
|  | 
 | ||||||
|  | 			var handled = sut.OnKeyEvent(default(IWebBrowser), default(IBrowser), KeyType.KeyUp, (int) Keys.Add, default(int), CefEventFlags.ControlDown, false); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsFalse(handled); | ||||||
|  | 			Assert.IsTrue(zoomIn); | ||||||
|  | 			Assert.IsFalse(zoomOut); | ||||||
|  | 			Assert.IsFalse(zoomReset); | ||||||
|  | 
 | ||||||
|  | 			zoomIn = false; | ||||||
|  | 			handled = sut.OnKeyEvent(default(IWebBrowser), default(IBrowser), KeyType.KeyUp, (int) Keys.D1, default(int), CefEventFlags.ControlDown | CefEventFlags.ShiftDown, false); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsFalse(handled); | ||||||
|  | 			Assert.IsTrue(zoomIn); | ||||||
|  | 			Assert.IsFalse(zoomOut); | ||||||
|  | 			Assert.IsFalse(zoomReset); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void MustDetectZoomOutCommand() | ||||||
|  | 		{ | ||||||
|  | 			var zoomIn = false; | ||||||
|  | 			var zoomOut = false; | ||||||
|  | 			var zoomReset = false; | ||||||
|  | 
 | ||||||
|  | 			sut.ZoomInRequested += () => zoomIn = true; | ||||||
|  | 			sut.ZoomOutRequested += () => zoomOut = true; | ||||||
|  | 			sut.ZoomResetRequested += () => zoomReset = true; | ||||||
|  | 
 | ||||||
|  | 			var handled = sut.OnKeyEvent(default(IWebBrowser), default(IBrowser), KeyType.KeyUp, (int) Keys.Subtract, default(int), CefEventFlags.ControlDown, false); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsFalse(handled); | ||||||
|  | 			Assert.IsFalse(zoomIn); | ||||||
|  | 			Assert.IsTrue(zoomOut); | ||||||
|  | 			Assert.IsFalse(zoomReset); | ||||||
|  | 
 | ||||||
|  | 			zoomOut = false; | ||||||
|  | 			handled = sut.OnKeyEvent(default(IWebBrowser), default(IBrowser), KeyType.KeyUp, (int) Keys.OemMinus, default(int), CefEventFlags.ControlDown, false); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsFalse(handled); | ||||||
|  | 			Assert.IsFalse(zoomIn); | ||||||
|  | 			Assert.IsTrue(zoomOut); | ||||||
|  | 			Assert.IsFalse(zoomReset); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void MustDetectZoomResetCommand() | ||||||
|  | 		{ | ||||||
|  | 			var zoomIn = false; | ||||||
|  | 			var zoomOut = false; | ||||||
|  | 			var zoomReset = false; | ||||||
|  | 
 | ||||||
|  | 			sut.ZoomInRequested += () => zoomIn = true; | ||||||
|  | 			sut.ZoomOutRequested += () => zoomOut = true; | ||||||
|  | 			sut.ZoomResetRequested += () => zoomReset = true; | ||||||
|  | 
 | ||||||
|  | 			var handled = sut.OnKeyEvent(default(IWebBrowser), default(IBrowser), KeyType.KeyUp, (int) Keys.D0, default(int), CefEventFlags.ControlDown, false); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsFalse(handled); | ||||||
|  | 			Assert.IsFalse(zoomIn); | ||||||
|  | 			Assert.IsFalse(zoomOut); | ||||||
|  | 			Assert.IsTrue(zoomReset); | ||||||
|  | 
 | ||||||
|  | 			zoomReset = false; | ||||||
|  | 			handled = sut.OnKeyEvent(default(IWebBrowser), default(IBrowser), KeyType.KeyUp, (int) Keys.NumPad0, default(int), CefEventFlags.ControlDown, false); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsFalse(handled); | ||||||
|  | 			Assert.IsFalse(zoomIn); | ||||||
|  | 			Assert.IsFalse(zoomOut); | ||||||
|  | 			Assert.IsTrue(zoomReset); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -0,0 +1,49 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  *  | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | using CefSharp; | ||||||
|  | using Microsoft.VisualStudio.TestTools.UnitTesting; | ||||||
|  | using SafeExamBrowser.Browser.Events; | ||||||
|  | using SafeExamBrowser.Browser.Handlers; | ||||||
|  | 
 | ||||||
|  | namespace SafeExamBrowser.Browser.UnitTests.Handlers | ||||||
|  | { | ||||||
|  | 	[TestClass] | ||||||
|  | 	public class LifeSpanHandlerTests | ||||||
|  | 	{ | ||||||
|  | 		private LifeSpanHandler sut; | ||||||
|  | 
 | ||||||
|  | 		[TestInitialize] | ||||||
|  | 		public void Initialize() | ||||||
|  | 		{ | ||||||
|  | 			sut = new LifeSpanHandler(); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void MustUseDefaultBehavior() | ||||||
|  | 		{ | ||||||
|  | 			Assert.IsFalse(sut.DoClose(default(IWebBrowser), default(IBrowser))); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void MustHandlePopup() | ||||||
|  | 		{ | ||||||
|  | 			var args = default(PopupRequestedEventArgs); | ||||||
|  | 			var jsAccess = false; | ||||||
|  | 			var url = "https://www.host.org/some-url"; | ||||||
|  | 
 | ||||||
|  | 			sut.PopupRequested += (a) => args = a; | ||||||
|  | 
 | ||||||
|  | 			var result = sut.OnBeforePopup(default(IWebBrowser), default(IBrowser), default(IFrame), url, default(string), default(WindowOpenDisposition), default(bool), default(IPopupFeatures), default(IWindowInfo), default(IBrowserSettings), ref jsAccess, out var newBrowser); | ||||||
|  | 
 | ||||||
|  | 			Assert.IsTrue(result); | ||||||
|  | 			Assert.AreEqual(default(IWebBrowser), newBrowser); | ||||||
|  | 			Assert.AreEqual(url, args.Url); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -0,0 +1,48 @@ | ||||||
|  | /* | ||||||
|  |  * Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET) | ||||||
|  |  *  | ||||||
|  |  * This Source Code Form is subject to the terms of the Mozilla Public | ||||||
|  |  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||||
|  |  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | using Microsoft.VisualStudio.TestTools.UnitTesting; | ||||||
|  | using Moq; | ||||||
|  | using SafeExamBrowser.Browser.Contracts.Filters; | ||||||
|  | using SafeExamBrowser.Browser.Handlers; | ||||||
|  | using SafeExamBrowser.Configuration.Contracts; | ||||||
|  | using SafeExamBrowser.I18n.Contracts; | ||||||
|  | using SafeExamBrowser.Logging.Contracts; | ||||||
|  | using SafeExamBrowser.Settings.Browser; | ||||||
|  | 
 | ||||||
|  | namespace SafeExamBrowser.Browser.UnitTests.Handlers | ||||||
|  | { | ||||||
|  | 	[TestClass] | ||||||
|  | 	public class RequestHandlerTests | ||||||
|  | 	{ | ||||||
|  | 		private AppConfig appConfig; | ||||||
|  | 		private Mock<IRequestFilter> filter; | ||||||
|  | 		private Mock<ILogger> logger; | ||||||
|  | 		private BrowserSettings settings; | ||||||
|  | 		private Mock<IText> text; | ||||||
|  | 		private RequestHandler sut; | ||||||
|  | 
 | ||||||
|  | 		[TestInitialize] | ||||||
|  | 		public void Initialize() | ||||||
|  | 		{ | ||||||
|  | 			appConfig = new AppConfig(); | ||||||
|  | 			filter = new Mock<IRequestFilter>(); | ||||||
|  | 			logger = new Mock<ILogger>(); | ||||||
|  | 			settings = new BrowserSettings(); | ||||||
|  | 			text = new Mock<IText>(); | ||||||
|  | 
 | ||||||
|  | 			sut = new RequestHandler(appConfig, filter.Object, logger.Object, settings, text.Object); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		[TestMethod] | ||||||
|  | 		public void TODO() | ||||||
|  | 		{ | ||||||
|  | 			// Use inheritance to test functionality! | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | @ -82,6 +82,7 @@ | ||||||
|     <Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL"> |     <Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL"> | ||||||
|       <HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.3\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath> |       <HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.3\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath> | ||||||
|     </Reference> |     </Reference> | ||||||
|  |     <Reference Include="System.Windows.Forms" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <Compile Include="Filters\LegacyFilter.cs" /> |     <Compile Include="Filters\LegacyFilter.cs" /> | ||||||
|  | @ -90,6 +91,12 @@ | ||||||
|     <Compile Include="Filters\Rules\RegexRuleTests.cs" /> |     <Compile Include="Filters\Rules\RegexRuleTests.cs" /> | ||||||
|     <Compile Include="Filters\Rules\SimplifiedRuleTests.cs" /> |     <Compile Include="Filters\Rules\SimplifiedRuleTests.cs" /> | ||||||
|     <Compile Include="Handlers\ContextMenuHandlerTests.cs" /> |     <Compile Include="Handlers\ContextMenuHandlerTests.cs" /> | ||||||
|  |     <Compile Include="Handlers\DialogHandlerTests.cs" /> | ||||||
|  |     <Compile Include="Handlers\DisplayHandlerTests.cs" /> | ||||||
|  |     <Compile Include="Handlers\DownloadHandlerTests.cs" /> | ||||||
|  |     <Compile Include="Handlers\KeyboardHandlerTests.cs" /> | ||||||
|  |     <Compile Include="Handlers\LifeSpanHandlerTests.cs" /> | ||||||
|  |     <Compile Include="Handlers\RequestHandlerTests.cs" /> | ||||||
|     <Compile Include="Properties\AssemblyInfo.cs" /> |     <Compile Include="Properties\AssemblyInfo.cs" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|  | @ -109,10 +116,26 @@ | ||||||
|       <Project>{04e653f1-98e6-4e34-9dd7-7f2bc1a8b767}</Project> |       <Project>{04e653f1-98e6-4e34-9dd7-7f2bc1a8b767}</Project> | ||||||
|       <Name>SafeExamBrowser.Browser</Name> |       <Name>SafeExamBrowser.Browser</Name> | ||||||
|     </ProjectReference> |     </ProjectReference> | ||||||
|  |     <ProjectReference Include="..\SafeExamBrowser.Configuration.Contracts\SafeExamBrowser.Configuration.Contracts.csproj"> | ||||||
|  |       <Project>{7d74555e-63e1-4c46-bd0a-8580552368c8}</Project> | ||||||
|  |       <Name>SafeExamBrowser.Configuration.Contracts</Name> | ||||||
|  |     </ProjectReference> | ||||||
|  |     <ProjectReference Include="..\SafeExamBrowser.I18n.Contracts\SafeExamBrowser.I18n.Contracts.csproj"> | ||||||
|  |       <Project>{1858ddf3-bc2a-4bff-b663-4ce2ffeb8b7d}</Project> | ||||||
|  |       <Name>SafeExamBrowser.I18n.Contracts</Name> | ||||||
|  |     </ProjectReference> | ||||||
|  |     <ProjectReference Include="..\SafeExamBrowser.Logging.Contracts\SafeExamBrowser.Logging.Contracts.csproj"> | ||||||
|  |       <Project>{64ea30fb-11d4-436a-9c2b-88566285363e}</Project> | ||||||
|  |       <Name>SafeExamBrowser.Logging.Contracts</Name> | ||||||
|  |     </ProjectReference> | ||||||
|     <ProjectReference Include="..\SafeExamBrowser.Settings\SafeExamBrowser.Settings.csproj"> |     <ProjectReference Include="..\SafeExamBrowser.Settings\SafeExamBrowser.Settings.csproj"> | ||||||
|       <Project>{30b2d907-5861-4f39-abad-c4abf1b3470e}</Project> |       <Project>{30b2d907-5861-4f39-abad-c4abf1b3470e}</Project> | ||||||
|       <Name>SafeExamBrowser.Settings</Name> |       <Name>SafeExamBrowser.Settings</Name> | ||||||
|     </ProjectReference> |     </ProjectReference> | ||||||
|  |     <ProjectReference Include="..\SafeExamBrowser.UserInterface.Contracts\SafeExamBrowser.UserInterface.Contracts.csproj"> | ||||||
|  |       <Project>{c7889e97-6ff6-4a58-b7cb-521ed276b316}</Project> | ||||||
|  |       <Name>SafeExamBrowser.UserInterface.Contracts</Name> | ||||||
|  |     </ProjectReference> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" /> |   <Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" /> | ||||||
|   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> |   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Damian Büchel
						Damian Büchel