Merge pull request #326 from microsoft/prupipho-169-IncreaseCodeCoverage

Increase code coverage:
This commit is contained in:
sibille 2021-06-14 11:57:23 +02:00 коммит произвёл GitHub
Родитель 39643f9e4b 8b86289afc
Коммит fc2bc80ba7
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
43 изменённых файлов: 1928 добавлений и 163 удалений

Просмотреть файл

@ -12,7 +12,7 @@ namespace Microsoft.Templates.Core
{ {
public static int SafeIndexOf(this IEnumerable<string> source, string item, int skip, bool ignoreWhiteLines = true, bool compareUpToItemLength = false) public static int SafeIndexOf(this IEnumerable<string> source, string item, int skip, bool ignoreWhiteLines = true, bool compareUpToItemLength = false)
{ {
if (string.IsNullOrWhiteSpace(item) && ignoreWhiteLines) if (source == null || (string.IsNullOrWhiteSpace(item) && ignoreWhiteLines))
{ {
return -1; return -1;
} }

Просмотреть файл

@ -3,49 +3,30 @@
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System; using System;
using System.IO;
using System.Linq; using System.Linq;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Text; using System.Text;
using Microsoft.Templates.Core.Resources;
namespace Microsoft.Templates.Core namespace Microsoft.Templates.Core
{ {
public static class StringExtensions public static class StringExtensions
{ {
public static string ObfuscateSHA(this string data)
{
string result = data;
byte[] b64data = Encoding.UTF8.GetBytes(data);
using (SHA512 sha2 = SHA512.Create())
{
result = GetHash(sha2, b64data);
}
return result.ToUpperInvariant();
}
private static string GetHash(HashAlgorithm md5Hash, byte[] inputData)
{
byte[] data = md5Hash.ComputeHash(inputData);
var sb = new StringBuilder();
for (int i = 0; i < data.Length; i++)
{
sb.Append(data[i].ToString("x2"));
}
return sb.ToString();
}
public static string[] GetMultiValue(this string value) public static string[] GetMultiValue(this string value)
{ {
if (string.IsNullOrWhiteSpace(value)) if (string.IsNullOrWhiteSpace(value) || string.IsNullOrEmpty(value.Trim()))
{ {
return new string[0]; return new string[0];
} }
return value.Split("|".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); var values = value.Split("|".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
if (values.Any(v => v != v.Trim()))
{
throw new InvalidDataException(string.Format(StringRes.ErrorExtraWhitespacesInMultiValues, value));
}
return values;
} }
public static bool IsMultiValue(this string value) public static bool IsMultiValue(this string value)

Просмотреть файл

@ -10,17 +10,12 @@ namespace Microsoft.Templates.Core
{ {
public static bool IsZero(this Version v) public static bool IsZero(this Version v)
{ {
return !v.IsNull() && (v.Major + v.Minor + v.Build + v.Revision) == 0; return !v.IsNull() && v.Major <= 0 && v.Minor <= 0 && v.Build <= 0 && v.Revision <= 0;
} }
public static bool IsNull(this Version v) public static bool IsNull(this Version v)
{ {
return v is null; return v is null;
} }
public static bool IsNullOrZero(this Version v)
{
return v.IsNull() || (v.Major + v.Minor + v.Build + v.Revision) == 0;
}
} }
} }

Просмотреть файл

@ -1,49 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Linq;
using System.Xml.Linq;
namespace Microsoft.Templates.Core
{
public static class XElementExtensions
{
public static XElement Select(this XElement xelement, string path)
{
var pathChunks = path.Split("/".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
if (pathChunks.Length <= 1)
{
return xelement;
}
var result = xelement;
for (int i = 1; i < pathChunks.Length; i++)
{
var chunk = pathChunks[i];
result = result.Element(xelement.GetDefaultNamespace() + chunk);
if (result == null)
{
return null;
}
}
return result;
}
public static void CopyNamespaces(this XElement xelement, XElement source)
{
foreach (var ns in source.Attributes().Where(a => a.IsNamespaceDeclaration).ToList())
{
if (!xelement.Attributes().Any(a => a.IsNamespaceDeclaration && a.Name.LocalName == ns.Name.LocalName))
{
xelement.Add(ns);
}
}
}
}
}

Просмотреть файл

@ -108,7 +108,7 @@ namespace Microsoft.Templates.Core.Gen
string projectGuid = ToolBox.Shell.Project.GetProjectGuidByName(GenContext.Current.ProjectName).ToString(); string projectGuid = ToolBox.Shell.Project.GetProjectGuidByName(GenContext.Current.ProjectName).ToString();
var projectTempFolder = Path.Combine(_tempGenerationFolder, projectGuid); var projectTempFolder = Path.Combine(_tempGenerationFolder, projectGuid);
Fs.EnsureFolder(projectTempFolder); Fs.EnsureFolderExists(projectTempFolder);
var tempGenerationName = $"{projectName}_{DateTime.Now.FormatAsShortDateTime()}"; var tempGenerationName = $"{projectName}_{DateTime.Now.FormatAsShortDateTime()}";
var inferredName = NamingService.Infer(tempGenerationName, new List<Validator> { new FolderNameValidator(projectTempFolder) }, "_"); var inferredName = NamingService.Infer(tempGenerationName, new List<Validator> { new FolderNameValidator(projectTempFolder) }, "_");

Просмотреть файл

@ -4,10 +4,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using Microsoft.Templates.Core.Diagnostics; using Microsoft.Templates.Core.Diagnostics;
using Microsoft.Templates.Core.Resources; using Microsoft.Templates.Core.Resources;
@ -16,11 +14,19 @@ namespace Microsoft.Templates.Core.Helpers
{ {
public static class Fs public static class Fs
{ {
public static void EnsureFolder(string folder) public static void EnsureFolderExists(string folder)
{ {
if (!Directory.Exists(folder)) try
{ {
Directory.CreateDirectory(folder); if (!Directory.Exists(folder))
{
Directory.CreateDirectory(folder);
}
}
catch (Exception ex)
{
var message = string.Format(StringRes.ErrorCreatingFolder, folder, ex.Message);
AppHealth.Current.Warning.TrackAsync(message, ex).FireAndForget();
} }
} }
@ -39,42 +45,11 @@ namespace Microsoft.Templates.Core.Helpers
} }
} }
public static async Task<int> CopyRecursiveAsync(string sourceDir, string targetDir, int totalNumber, int counter, int latestProgress, bool overwrite = false, Action<int> reportProgress = null)
{
Directory.CreateDirectory(targetDir);
foreach (var file in Directory.GetFiles(sourceDir))
{
counter++;
var progress = Convert.ToInt32((counter * 100) / totalNumber);
if (progress != latestProgress)
{
reportProgress?.Invoke(progress);
latestProgress = progress;
}
await Task.Run(() =>
{
File.Copy(file, Path.Combine(targetDir, Path.GetFileName(file)), overwrite);
});
}
foreach (var directory in Directory.GetDirectories(sourceDir))
{
counter = await CopyRecursiveAsync(directory, Path.Combine(targetDir, Path.GetFileName(directory)), totalNumber, counter, latestProgress, overwrite, reportProgress);
}
return counter;
}
public static void SafeCopyFile(string sourceFile, string destFolder, bool overwrite) public static void SafeCopyFile(string sourceFile, string destFolder, bool overwrite)
{ {
try try
{ {
if (!Directory.Exists(destFolder)) EnsureFolderExists(destFolder);
{
Directory.CreateDirectory(destFolder);
}
var destFile = Path.Combine(destFolder, Path.GetFileName(sourceFile)); var destFile = Path.Combine(destFolder, Path.GetFileName(sourceFile));
@ -131,23 +106,6 @@ namespace Microsoft.Templates.Core.Helpers
} }
} }
public static async Task SafeMoveDirectoryAsync(string sourceDir, string targetDir, bool overwrite = false, Action<int> reportProgress = null)
{
try
{
if (Directory.Exists(sourceDir))
{
var totalFiles = Directory.GetFiles(sourceDir, "*.*", SearchOption.AllDirectories).Length;
await CopyRecursiveAsync(sourceDir, targetDir, totalFiles, 0, 0, overwrite, reportProgress);
SafeDeleteDirectory(sourceDir);
}
}
catch (Exception ex)
{
AppHealth.Current.Warning.TrackAsync(string.Format(StringRes.FsSafeMoveDirectoryMessage, sourceDir, targetDir, ex.Message), ex).FireAndForget();
}
}
public static void EnsureFileEditable(string filePath) public static void EnsureFileEditable(string filePath)
{ {
try try
@ -160,8 +118,8 @@ namespace Microsoft.Templates.Core.Helpers
} }
catch (Exception ex) catch (Exception ex)
{ {
var msg = string.Format(StringRes.FsEnsureFileEditableException, filePath); var message = string.Format(StringRes.FsEnsureFileEditableException, filePath);
AppHealth.Current.Warning.TrackAsync(msg, ex).FireAndForget(); AppHealth.Current.Warning.TrackAsync(message, ex).FireAndForget();
} }
} }

Просмотреть файл

@ -75,7 +75,7 @@ namespace Microsoft.Templates.Core.Locations
var tempFolder = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); var tempFolder = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
var sourceUrl = $"{_cdnUrl}/{packageInfo.Name}"; var sourceUrl = $"{_cdnUrl}/{packageInfo.Name}";
var fileTarget = Path.Combine(tempFolder, packageInfo.Name); var fileTarget = Path.Combine(tempFolder, packageInfo.Name);
Fs.EnsureFolder(tempFolder); Fs.EnsureFolderExists(tempFolder);
await DownloadContentAsync(sourceUrl, fileTarget, ct); await DownloadContentAsync(sourceUrl, fileTarget, ct);
packageInfo.LocalPath = fileTarget; packageInfo.LocalPath = fileTarget;
@ -87,7 +87,7 @@ namespace Microsoft.Templates.Core.Locations
var tempFolder = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); var tempFolder = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
var sourceUrl = $"{_cdnUrl}/config.json"; var sourceUrl = $"{_cdnUrl}/config.json";
var fileTarget = Path.Combine(tempFolder, "config.json"); var fileTarget = Path.Combine(tempFolder, "config.json");
Fs.EnsureFolder(tempFolder); Fs.EnsureFolderExists(tempFolder);
await DownloadContentAsync(sourceUrl, fileTarget, ct); await DownloadContentAsync(sourceUrl, fileTarget, ct);

Просмотреть файл

@ -336,7 +336,7 @@ namespace Microsoft.Templates.Core.Locations
fileInfo.Delete(); fileInfo.Delete();
} }
Fs.EnsureFolder(_content.TemplatesFolder); Fs.EnsureFolderExists(_content.TemplatesFolder);
File.WriteAllText(fileInfo.FullName, "Instance syncing"); File.WriteAllText(fileInfo.FullName, "Instance syncing");
} }
catch (Exception ex) catch (Exception ex)

Просмотреть файл

@ -11,6 +11,7 @@ using System.Net.Mime;
using System.Security; using System.Security;
using System.Security.Cryptography; using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -262,7 +263,7 @@ namespace Microsoft.Templates.Core.Packaging
var certInfo = new CertInfo() var certInfo = new CertInfo()
{ {
Cert = new X509Certificate2(cert), Cert = new X509Certificate2(cert),
Pin = cert.GetPublicKeyString().ObfuscateSHA(), Pin = Obfuscate(cert.GetPublicKeyString()),
Status = _digitalSignatureService.VerifyCertificate(cert), Status = _digitalSignatureService.VerifyCertificate(cert),
}; };
@ -340,11 +341,43 @@ namespace Microsoft.Templates.Core.Packaging
return status == X509ChainStatusFlags.NoError; return status == X509ChainStatusFlags.NoError;
} }
private static string GetHash(HashAlgorithm md5Hash, byte[] inputData)
{
byte[] data = md5Hash.ComputeHash(inputData);
var sb = new StringBuilder();
for (int i = 0; i < data.Length; i++)
{
sb.Append(data[i].ToString("x2"));
}
return sb.ToString();
}
private static string Obfuscate(string data)
{
if (string.IsNullOrWhiteSpace(data))
{
return string.Empty;
}
string result = data;
byte[] b64data = Encoding.UTF8.GetBytes(data);
using (SHA512 sha2 = SHA512.Create())
{
result = GetHash(sha2, b64data);
}
return result.ToUpperInvariant();
}
private bool VerifyAllowedPublicKey(X509Certificate cert) private bool VerifyAllowedPublicKey(X509Certificate cert)
{ {
var pubKeyCert = cert.GetPublicKeyString(); var pubKeyCert = cert.GetPublicKeyString();
var pubKeyPin = pubKeyCert.ObfuscateSHA(); var pubKeyPin = Obfuscate(pubKeyCert);
AppHealth.Current.Verbose.TrackAsync($"{StringRes.PackageCertificateString} {cert.Subject}").FireAndForget(); AppHealth.Current.Verbose.TrackAsync($"{StringRes.PackageCertificateString} {cert.Subject}").FireAndForget();
AppHealth.Current.Verbose.TrackAsync($"Key: {pubKeyCert}").FireAndForget(); AppHealth.Current.Verbose.TrackAsync($"Key: {pubKeyCert}").FireAndForget();

Просмотреть файл

@ -114,6 +114,15 @@ namespace Microsoft.Templates.Core.Resources {
} }
} }
/// <summary>
/// Looks up a localized string similar to Error creating folder &apos;{0}&apos;: {1}.
/// </summary>
public static string ErrorCreatingFolder {
get {
return ResourceManager.GetString("ErrorCreatingFolder", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Circular dependency detected on template {0} with {1}.. /// Looks up a localized string similar to Circular dependency detected on template {0} with {1}..
/// </summary> /// </summary>
@ -213,6 +222,15 @@ namespace Microsoft.Templates.Core.Resources {
} }
} }
/// <summary>
/// Looks up a localized string similar to Multivalue field: &apos;{0}&apos; contains trailing or leading whitespaces..
/// </summary>
public static string ErrorExtraWhitespacesInMultiValues {
get {
return ResourceManager.GetString("ErrorExtraWhitespacesInMultiValues", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Template &apos;{0}&apos;, name: &apos;{1}&apos;, reason: &apos;{2}&apos;. /// Looks up a localized string similar to Template &apos;{0}&apos;, name: &apos;{1}&apos;, reason: &apos;{2}&apos;.
/// </summary> /// </summary>
@ -457,7 +475,7 @@ namespace Microsoft.Templates.Core.Resources {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to The folder {0} can&apos;t be delete. Error: {1}. /// Looks up a localized string similar to The folder {0} can&apos;t be deleted. Error: {1}.
/// </summary> /// </summary>
public static string FsSafeDeleteDirectoryMessage { public static string FsSafeDeleteDirectoryMessage {
get { get {
@ -466,7 +484,7 @@ namespace Microsoft.Templates.Core.Resources {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to The file {0} can&apos;t be delete. Error: {1}. /// Looks up a localized string similar to The file {0} can&apos;t be deleted. Error: {1}.
/// </summary> /// </summary>
public static string FsSafeDeleteFileMessage { public static string FsSafeDeleteFileMessage {
get { get {
@ -493,7 +511,7 @@ namespace Microsoft.Templates.Core.Resources {
} }
/// <summary> /// <summary>
/// Looks up a localized string similar to The folder {0} can&apos;t be rename. Error: {1}. /// Looks up a localized string similar to The folder {0} can&apos;t be renamed. Error: {1}.
/// </summary> /// </summary>
public static string FsSafeRenameDirectoryMessage { public static string FsSafeRenameDirectoryMessage {
get { get {

Просмотреть файл

@ -581,4 +581,12 @@ Nemohly být integrovány následující změny: {2}
<data name="TemplatesSynchronizationError" xml:space="preserve"> <data name="TemplatesSynchronizationError" xml:space="preserve">
<value>Error synchronizing templates.</value> <value>Error synchronizing templates.</value>
</data> </data>
<data name="ErrorCreatingFolder" xml:space="preserve">
<value>Error creating folder '{0}': {1}</value>
<comment>{0} Name of the folder, {1} exception message</comment>
</data>
<data name="ErrorExtraWhitespacesInMultiValues" xml:space="preserve">
<value>Multivalue field: '{0}' contains trailing or leading whitespaces.</value>
<comment>{0}: multivalue string</comment>
</data>
</root> </root>

Просмотреть файл

@ -581,4 +581,12 @@ Die folgenden Änderungen konnten nicht integriert werden: {2}
<data name="TemplatesSynchronizationError" xml:space="preserve"> <data name="TemplatesSynchronizationError" xml:space="preserve">
<value>Error synchronizing templates.</value> <value>Error synchronizing templates.</value>
</data> </data>
<data name="ErrorCreatingFolder" xml:space="preserve">
<value>Error creating folder '{0}': {1}</value>
<comment>{0} Name of the folder, {1} exception message</comment>
</data>
<data name="ErrorExtraWhitespacesInMultiValues" xml:space="preserve">
<value>Multivalue field: '{0}' contains trailing or leading whitespaces.</value>
<comment>{0}: multivalue string</comment>
</data>
</root> </root>

Просмотреть файл

@ -581,4 +581,12 @@ No se pueden integrar las modificaciones siguientes: {2}
<data name="TemplatesSynchronizationError" xml:space="preserve"> <data name="TemplatesSynchronizationError" xml:space="preserve">
<value>Error synchronizing templates.</value> <value>Error synchronizing templates.</value>
</data> </data>
<data name="ErrorCreatingFolder" xml:space="preserve">
<value>Error creating folder '{0}': {1}</value>
<comment>{0} Name of the folder, {1} exception message</comment>
</data>
<data name="ErrorExtraWhitespacesInMultiValues" xml:space="preserve">
<value>Multivalue field: '{0}' contains trailing or leading whitespaces.</value>
<comment>{0}: multivalue string</comment>
</data>
</root> </root>

Просмотреть файл

@ -581,4 +581,12 @@ Les modifications suivantes n'ont pu être intégrées : {2}
<data name="TemplatesSynchronizationError" xml:space="preserve"> <data name="TemplatesSynchronizationError" xml:space="preserve">
<value>Error synchronizing templates.</value> <value>Error synchronizing templates.</value>
</data> </data>
<data name="ErrorCreatingFolder" xml:space="preserve">
<value>Error creating folder '{0}': {1}</value>
<comment>{0} Name of the folder, {1} exception message</comment>
</data>
<data name="ErrorExtraWhitespacesInMultiValues" xml:space="preserve">
<value>Multivalue field: '{0}' contains trailing or leading whitespaces.</value>
<comment>{0}: multivalue string</comment>
</data>
</root> </root>

Просмотреть файл

@ -581,4 +581,12 @@ Impossibile integrare le seguenti modifiche: {2}
<data name="TemplatesSynchronizationError" xml:space="preserve"> <data name="TemplatesSynchronizationError" xml:space="preserve">
<value>Error synchronizing templates.</value> <value>Error synchronizing templates.</value>
</data> </data>
<data name="ErrorCreatingFolder" xml:space="preserve">
<value>Error creating folder '{0}': {1}</value>
<comment>{0} Name of the folder, {1} exception message</comment>
</data>
<data name="ErrorExtraWhitespacesInMultiValues" xml:space="preserve">
<value>Multivalue field: '{0}' contains trailing or leading whitespaces.</value>
<comment>{0}: multivalue string</comment>
</data>
</root> </root>

Просмотреть файл

@ -581,4 +581,12 @@
<data name="TemplatesSynchronizationError" xml:space="preserve"> <data name="TemplatesSynchronizationError" xml:space="preserve">
<value>Error synchronizing templates.</value> <value>Error synchronizing templates.</value>
</data> </data>
<data name="ErrorCreatingFolder" xml:space="preserve">
<value>Error creating folder '{0}': {1}</value>
<comment>{0} Name of the folder, {1} exception message</comment>
</data>
<data name="ErrorExtraWhitespacesInMultiValues" xml:space="preserve">
<value>Multivalue field: '{0}' contains trailing or leading whitespaces.</value>
<comment>{0}: multivalue string</comment>
</data>
</root> </root>

Просмотреть файл

@ -581,4 +581,12 @@
<data name="TemplatesSynchronizationError" xml:space="preserve"> <data name="TemplatesSynchronizationError" xml:space="preserve">
<value>Error synchronizing templates.</value> <value>Error synchronizing templates.</value>
</data> </data>
<data name="ErrorCreatingFolder" xml:space="preserve">
<value>Error creating folder '{0}': {1}</value>
<comment>{0} Name of the folder, {1} exception message</comment>
</data>
<data name="ErrorExtraWhitespacesInMultiValues" xml:space="preserve">
<value>Multivalue field: '{0}' contains trailing or leading whitespaces.</value>
<comment>{0}: multivalue string</comment>
</data>
</root> </root>

Просмотреть файл

@ -581,4 +581,12 @@ Nie można zinterpretować następujących zmian: {2}
<data name="TemplatesSynchronizationError" xml:space="preserve"> <data name="TemplatesSynchronizationError" xml:space="preserve">
<value>Error synchronizing templates.</value> <value>Error synchronizing templates.</value>
</data> </data>
<data name="ErrorCreatingFolder" xml:space="preserve">
<value>Error creating folder '{0}': {1}</value>
<comment>{0} Name of the folder, {1} exception message</comment>
</data>
<data name="ErrorExtraWhitespacesInMultiValues" xml:space="preserve">
<value>Multivalue field: '{0}' contains trailing or leading whitespaces.</value>
<comment>{0}: multivalue string</comment>
</data>
</root> </root>

Просмотреть файл

@ -581,4 +581,12 @@ As seguintes alterações não puderam ser integradas: {2}
<data name="TemplatesSynchronizationError" xml:space="preserve"> <data name="TemplatesSynchronizationError" xml:space="preserve">
<value>Error synchronizing templates.</value> <value>Error synchronizing templates.</value>
</data> </data>
<data name="ErrorCreatingFolder" xml:space="preserve">
<value>Error creating folder '{0}': {1}</value>
<comment>{0} Name of the folder, {1} exception message</comment>
</data>
<data name="ErrorExtraWhitespacesInMultiValues" xml:space="preserve">
<value>Multivalue field: '{0}' contains trailing or leading whitespaces.</value>
<comment>{0}: multivalue string</comment>
</data>
</root> </root>

Просмотреть файл

@ -158,11 +158,11 @@
<comment>{0}: Source File Path, {1}: Destination folder name, {2}: Error</comment> <comment>{0}: Source File Path, {1}: Destination folder name, {2}: Error</comment>
</data> </data>
<data name="FsSafeDeleteDirectoryMessage" xml:space="preserve"> <data name="FsSafeDeleteDirectoryMessage" xml:space="preserve">
<value>The folder {0} can't be delete. Error: {1}</value> <value>The folder {0} can't be deleted. Error: {1}</value>
<comment>{0}: Folder Name, {1}: Error</comment> <comment>{0}: Folder Name, {1}: Error</comment>
</data> </data>
<data name="FsSafeDeleteFileMessage" xml:space="preserve"> <data name="FsSafeDeleteFileMessage" xml:space="preserve">
<value>The file {0} can't be delete. Error: {1}</value> <value>The file {0} can't be deleted. Error: {1}</value>
<comment>{0}: File Path, {1}: Error</comment> <comment>{0}: File Path, {1}: Error</comment>
</data> </data>
<data name="FsSafeMoveDirectoryMessage" xml:space="preserve"> <data name="FsSafeMoveDirectoryMessage" xml:space="preserve">
@ -438,7 +438,7 @@ The following changes could not be integrated: {2}
<value>Templates local path is empty.</value> <value>Templates local path is empty.</value>
</data> </data>
<data name="FsSafeRenameDirectoryMessage" xml:space="preserve"> <data name="FsSafeRenameDirectoryMessage" xml:space="preserve">
<value>The folder {0} can't be rename. Error: {1}</value> <value>The folder {0} can't be renamed. Error: {1}</value>
<comment>{0}: Folder Name, {1}: Error</comment> <comment>{0}: Folder Name, {1}: Error</comment>
</data> </data>
<data name="TemplatesSynchronizationErrorDownloadingConfig" xml:space="preserve"> <data name="TemplatesSynchronizationErrorDownloadingConfig" xml:space="preserve">
@ -581,4 +581,12 @@ The following changes could not be integrated: {2}
<data name="TemplatesSynchronizationError" xml:space="preserve"> <data name="TemplatesSynchronizationError" xml:space="preserve">
<value>Error synchronizing templates.</value> <value>Error synchronizing templates.</value>
</data> </data>
<data name="ErrorCreatingFolder" xml:space="preserve">
<value>Error creating folder '{0}': {1}</value>
<comment>{0} Name of the folder, {1} exception message</comment>
</data>
<data name="ErrorExtraWhitespacesInMultiValues" xml:space="preserve">
<value>Multivalue field: '{0}' contains trailing or leading whitespaces.</value>
<comment>{0}: multivalue string</comment>
</data>
</root> </root>

Просмотреть файл

@ -581,4 +581,12 @@
<data name="TemplatesSynchronizationError" xml:space="preserve"> <data name="TemplatesSynchronizationError" xml:space="preserve">
<value>Error synchronizing templates.</value> <value>Error synchronizing templates.</value>
</data> </data>
<data name="ErrorCreatingFolder" xml:space="preserve">
<value>Error creating folder '{0}': {1}</value>
<comment>{0} Name of the folder, {1} exception message</comment>
</data>
<data name="ErrorExtraWhitespacesInMultiValues" xml:space="preserve">
<value>Multivalue field: '{0}' contains trailing or leading whitespaces.</value>
<comment>{0}: multivalue string</comment>
</data>
</root> </root>

Просмотреть файл

@ -581,4 +581,12 @@ Aşağıdaki değişiklikler tümleştirilemedi: {2}
<data name="TemplatesSynchronizationError" xml:space="preserve"> <data name="TemplatesSynchronizationError" xml:space="preserve">
<value>Error synchronizing templates.</value> <value>Error synchronizing templates.</value>
</data> </data>
<data name="ErrorCreatingFolder" xml:space="preserve">
<value>Error creating folder '{0}': {1}</value>
<comment>{0} Name of the folder, {1} exception message</comment>
</data>
<data name="ErrorExtraWhitespacesInMultiValues" xml:space="preserve">
<value>Multivalue field: '{0}' contains trailing or leading whitespaces.</value>
<comment>{0}: multivalue string</comment>
</data>
</root> </root>

Просмотреть файл

@ -581,4 +581,12 @@
<data name="TemplatesSynchronizationError" xml:space="preserve"> <data name="TemplatesSynchronizationError" xml:space="preserve">
<value>Error synchronizing templates.</value> <value>Error synchronizing templates.</value>
</data> </data>
<data name="ErrorCreatingFolder" xml:space="preserve">
<value>Error creating folder '{0}': {1}</value>
<comment>{0} Name of the folder, {1} exception message</comment>
</data>
<data name="ErrorExtraWhitespacesInMultiValues" xml:space="preserve">
<value>Multivalue field: '{0}' contains trailing or leading whitespaces.</value>
<comment>{0}: multivalue string</comment>
</data>
</root> </root>

Просмотреть файл

@ -581,4 +581,12 @@
<data name="TemplatesSynchronizationError" xml:space="preserve"> <data name="TemplatesSynchronizationError" xml:space="preserve">
<value>Error synchronizing templates.</value> <value>Error synchronizing templates.</value>
</data> </data>
<data name="ErrorCreatingFolder" xml:space="preserve">
<value>Error creating folder '{0}': {1}</value>
<comment>{0} Name of the folder, {1} exception message</comment>
</data>
<data name="ErrorExtraWhitespacesInMultiValues" xml:space="preserve">
<value>Multivalue field: '{0}' contains trailing or leading whitespaces.</value>
<comment>{0}: multivalue string</comment>
</data>
</root> </root>

Просмотреть файл

@ -7,11 +7,6 @@
<Configurations>Debug;Release;Analyze</Configurations> <Configurations>Debug;Release;Analyze</Configurations>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<EmbeddedResource Remove="TestData\NewFolder\**" />
<None Remove="TestData\NewFolder\**" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<None Remove="TestData\Templates\test\itemNameValidation.config.json" /> <None Remove="TestData\Templates\test\itemNameValidation.config.json" />
<None Remove="TestData\Templates\test\projectNameValidation.config.json" /> <None Remove="TestData\Templates\test\projectNameValidation.config.json" />
@ -99,7 +94,7 @@
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.10.0" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="4.7.0" /> <PackageReference Include="System.Configuration.ConfigurationManager" Version="4.7.0" />
<PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.console" Version="2.4.1"> <PackageReference Include="xunit.runner.console" Version="2.4.1">
@ -163,8 +158,24 @@
<Compile Include="Diagnostics\TelemetryFixture.cs" /> <Compile Include="Diagnostics\TelemetryFixture.cs" />
<Compile Include="Diagnostics\TelemetryServiceTest.cs" /> <Compile Include="Diagnostics\TelemetryServiceTest.cs" />
<Compile Include="Diagnostics\TestHealthWriter.cs" /> <Compile Include="Diagnostics\TestHealthWriter.cs" />
<Compile Include="Extensions\IEnumerableExtensionsTests.cs" />
<Compile Include="Extensions\StringExtensions.cs" /> <Compile Include="Extensions\StringExtensions.cs" />
<Compile Include="Gen\GenComposerTests.cs" /> <Compile Include="Extensions\TemplateTypeExtensionsTests.cs" />
<Compile Include="Extensions\VersionExtensionsTests.cs" />
<Compile Include="Extensions\StringExtensionsTests.cs" />
<Compile Include="Extensions\DateTimeExtensionsTests.cs" />
<Compile Include="Extensions\DictionaryExtensionsTests.cs" />
<Compile Include="Gen\GenComposerTests.cs" />
<Compile Include="Helpers\FsTests\GetExistingFolderNamesTests.cs" />
<Compile Include="Helpers\FSTestsFixture.cs" />
<Compile Include="Helpers\FsTests\SafeMoveFileTests.cs" />
<Compile Include="Helpers\FsTests\SafeDeleteFileTests.cs" />
<Compile Include="Helpers\FsTests\SafeRenameDirectoryTests.cs" />
<Compile Include="Helpers\FsTests\SafeDeleteDirectoryTests.cs" />
<Compile Include="Helpers\FsTests\SafeCopyFileTests.cs" />
<Compile Include="Helpers\FsTests\EnsureFileEditableTests.cs" />
<Compile Include="Helpers\FsTests\EnsureFolderExistsTests.cs" />
<Compile Include="Helpers\FileHelpersTests.cs" />
<Compile Include="Naming\ItemNameServiceTests.cs" /> <Compile Include="Naming\ItemNameServiceTests.cs" />
<Compile Include="Naming\ProjectNameServiceTests.cs" /> <Compile Include="Naming\ProjectNameServiceTests.cs" />
<Compile Include="Naming\Validators\DefaultNamesValidatorTests.cs" /> <Compile Include="Naming\Validators\DefaultNamesValidatorTests.cs" />

Просмотреть файл

@ -0,0 +1,80 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using Xunit;
namespace Microsoft.Templates.Core.Test.Extensions
{
[Trait("ExecutionSet", "Minimum")]
public class DateTimeExtensionsTests
{
private readonly DateTime date;
public DateTimeExtensionsTests()
{
date = new DateTime(2000, 1, 2, 3, 4, 5, 6);
}
[Fact]
public void FormatAsDateForFilePath_ShouldReturnCorrectStringDate()
{
var factData = date;
var expected = "20000102";
var result = factData.FormatAsDateForFilePath();
Assert.Equal(expected: expected, actual: result);
}
[Fact]
public void FormatAsFullDateTime_ShouldReturnCorrectStringDate()
{
var factData = date;
var expected = "2000-01-02 03:04:05.006";
var result = factData.FormatAsFullDateTime();
Assert.Equal(result, expected);
}
[Fact]
public void FormatAsTime_ShouldReturnCorrectStringDate()
{
var factData = date;
var expected = "03:04:05.006";
var result = factData.FormatAsTime();
Assert.Equal(result, expected);
}
[Fact]
public void FormatAsShortDateTime_ShouldReturnCorrectStringDate()
{
var factData = date;
var expected = "20000102_030405";
var result = factData.FormatAsShortDateTime();
Assert.Equal(result, expected);
}
[Fact]
public void FormatAsDateHoursMinutes_ShouldReturnCorrectStringDate()
{
var factData = date;
var expected = "02030405";
var result = factData.FormatAsDateHoursMinutes();
Assert.Equal(result, expected);
}
}
}

Просмотреть файл

@ -0,0 +1,111 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using Microsoft.Templates.Core.Composition;
using Xunit;
namespace Microsoft.Templates.Core.Test.Extensions
{
[Trait("ExecutionSet", "Minimum")]
public class DictionaryExtensionsTests
{
private const int MAX = 100;
private readonly Random random;
private readonly Dictionary<string, string> dictionaryOfStrings;
private readonly Dictionary<string, QueryableProperty> dictionaryOfQueryable;
public DictionaryExtensionsTests()
{
random = new Random();
dictionaryOfStrings = new Dictionary<string, string>();
dictionaryOfQueryable = new Dictionary<string, QueryableProperty>();
}
private void SetUpStringData(int items)
{
for (var i = 0; i < items; i++)
{
dictionaryOfStrings.Add($"key{i + 1}", $"value{i + 1}");
}
}
[Fact]
public void SafeGet_DictionaryOfStrings_NotFound_ShouldReturnDefault()
{
string expected = null;
var actual = dictionaryOfStrings.SafeGet("test");
Assert.Equal(expected, actual);
}
[Fact]
public void SafeGet_DictionaryOfStrings_NotFound_ShouldReturnConfiguredDefault()
{
string expected = "default";
var actual = dictionaryOfStrings.SafeGet("test", "default");
Assert.Equal(expected, actual);
}
[Fact]
public void SafeGet_DictionaryOfStrings_Found_ShouldReturnItem()
{
var randomItemsNumber = random.Next(MAX);
SetUpStringData(randomItemsNumber);
var expected = $"value{randomItemsNumber}";
var actual = dictionaryOfStrings.SafeGet($"key{randomItemsNumber}");
Assert.Equal(expected, actual);
}
private void SetUpQueryableData(int items)
{
for (var i = 0; i < items; i++)
{
dictionaryOfQueryable.Add($"key{i + 1}", new QueryableProperty($"name{i + 1}", $"value{i + 1}"));
}
}
[Fact]
public void SafeGet_DictionaryOfQueryable_NotFound_ShouldReturnDefault()
{
QueryableProperty expected = null;
var actual = dictionaryOfQueryable.SafeGet("test");
Assert.Equal(expected, actual);
}
[Fact]
public void SafeGet_DictionaryOfQueryable_NotFound_ShouldReturnConfiguredDefault()
{
QueryableProperty expected = QueryableProperty.Empty;
var actual = dictionaryOfQueryable.SafeGet("test", QueryableProperty.Empty);
Assert.Equal(expected.Name, actual.Name);
Assert.Equal(expected.Value, actual.Value);
}
[Fact]
public void SafeGet_DictionaryOfQueryable_Found_ShouldReturnItem()
{
var randomItemsNumber = random.Next(MAX);
SetUpQueryableData(randomItemsNumber);
var expected = new QueryableProperty($"name{randomItemsNumber}", $"value{randomItemsNumber}");
var actual = dictionaryOfQueryable.SafeGet($"key{randomItemsNumber}");
Assert.Equal(expected.Name, actual.Name);
Assert.Equal(expected.Value, actual.Value);
}
}
}

Просмотреть файл

@ -0,0 +1,97 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using Xunit;
namespace Microsoft.Templates.Core.Test.Extensions
{
[Trait("ExecutionSet", "Minimum")]
public class IEnumerableExtensionsTests
{
[Theory]
[InlineData(new string[0], "public void SomeMethod()", 0)]
[InlineData(new string[0], "public void SomeMethod()", 5)]
[InlineData(null, "public void SomeMethod()", 0)]
[InlineData(null, "public void SomeMethod()", 5)]
[InlineData(new[] { " " }, "public void SomeMethod()", 0)]
[InlineData(new[] { " " }, "public void SomeMethod()", 5)]
public void SafeIndexOf_NoAvailableLinesToMatch_ShouldReturnNotFound(IEnumerable<string> lines, string lineToMatch, int linesToSkip)
{
var expected = -1;
var actual = lines.SafeIndexOf(lineToMatch, linesToSkip);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(new string[0], "public void SomeMethod()")]
[InlineData(new[] { "public void SomeMetod()", "{", "}" }, "public void SomeMethod()")]
[InlineData(new[] { "public void SomeMethod()", "{", "}" }, "no matching line")]
[InlineData(new[] { " public void SomeMethod()", "{", "}" }, "public void SomeMethod()")]
[InlineData(new[] { "", "", "public void SomeMethod()", "{", "}" }, "public void SmeMethod()")]
public void SafeIndexOf_NoMatchingLinesFound_ShouldReturnNotFound(IEnumerable<string> lines, string linesToMatch)
{
var expected = -1;
var linesToSkip = 0;
var actual = lines.SafeIndexOf(linesToMatch, linesToSkip);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData(new[] { "public void SomeMethod()", "{", "}" }, "no matching line", -1)]
[InlineData(new[] { "public void SomeMethod()", "{", "}" }, "public void SomeMethod()", 0)]
[InlineData(new[] { "", "", "public void SomeMethod()", "{", "}" }, "public void SomeMethod()", 2)]
public void SafeIndexOf_NoLinesToSkip_ShouldReturnIndexOfMatchingLine(IEnumerable<string> lines, string lineToMatch, int indexOfLine)
{
var actual = lines.SafeIndexOf(lineToMatch, 0);
Assert.Equal(indexOfLine, actual);
}
[Theory]
[InlineData(new[] { "public void SomeMethod()", "{", "}" }, "public void SomeMethod()", 0)]
[InlineData(new[] { "public void SomeMethod()", "{", "}" }, "{", 1)]
[InlineData(new[] { " ", "public void SomeMethod()", "{", "}" }, "{", 2)]
[InlineData(new[] { "public void SomeMethod()", "{", "}", "//line to match" }, "//line to match", 3)]
public void SafeIndexOf_SkipLinesIsNegativeNumber_ShouldReturnIndexOfMatchingLine(IEnumerable<string> lines, string lineToMatch, int indexOfLine)
{
var actual = lines.SafeIndexOf(lineToMatch, -1);
Assert.Equal(indexOfLine, actual);
}
[Theory]
[InlineData(new[] { "public void SomeMethod()", "", "{", "}" }, "public void SomeMethod()", 0, 0)]
[InlineData(new[] { "public void SomeMethod()", "", "{", "}" }, "public void SomeMethod()", 1, -1)]
[InlineData(new[] { "", "", "public void SomeMethod()", "{", "}" }, "public void SomeMethod()", 1, 2)]
[InlineData(new[] { "public void SomeMethod()", "{", "//line to match", "}", "//line to match" }, "//line to match", 1, 2)]
[InlineData(new[] { "public void SomeMethod()", "{", "//line to match", "}", "//line to match" }, "//line to match", 4, 4)]
[InlineData(new[] { "public void SomeMethod()", "{", "//line to match", "}", "//line to match" }, "//line to match", 5, -1)]
[InlineData(new[] { "public void SomeMethod()", "{", "}", "//line to match" }, "//line to match", 1, 3)]
[InlineData(new[] { "public void SomeMethod()", "{", "}", "//line to match" }, "//line to match", 4, -1)]
[InlineData(new[] { "", " ", "public void SomeMethod()", "//line to match", "{ ", "}", "//line to match" }, "//line to match", 1, 3)]
[InlineData(new[] { "//line to match", " ", "public void SomeMethod()", "//line to match", "{ ", "}", "//line to match" }, "//line to match", 1, 3)]
public void SafeIndexOf_SkippingLines_TakeIntoAccountWhiteLines_ShouldReturnIndexOfMatchingLine(IEnumerable<string> lines, string lineToMatch, int linesToSkip, int indexOfMatchingLine)
{
var actual = lines.SafeIndexOf(lineToMatch, linesToSkip, false);
Assert.Equal(indexOfMatchingLine, actual);
}
[Theory]
[InlineData(new[] { "public SomeClass(/*{[{*/ISomeService someService/*}]}*/)", "{", "}" }, "public SomeCass(", -1)]
[InlineData(new[] { "public SomeClass(/*{[{*/ISomeService someService/*}]}*/)", "{", "}" }, "public SomeClass(", 0)]
[InlineData(new[] { " public SomeClass(/*{[{*/ISomeService someService/*}]}*/)", "{", "}" }, "public SomeClass(", -1)]
[InlineData(new[] { "", "public SomeClass(/*{[{*/ISomeService someService/*}]}*/)", "{", "}" }, "public SomeClass(", 1)]
[InlineData(new[] { "", " ", "public SomeClass(/*{[{*/ISomeService someService/*}]}*/)", "{", "}" }, "public SomeClass(", 2)]
public void SafeIndexOf_ReplaceInline_CompareUpToItemLenghtIsTrue_ShouldReturnIndexOfMatchingLine(IEnumerable<string> lines, string lineToMatch, int indexOfMatchingLine)
{
var actual = lines.SafeIndexOf(lineToMatch, 0, true, true);
Assert.Equal(indexOfMatchingLine, actual);
}
}
}

Просмотреть файл

@ -0,0 +1,135 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.IO;
using Xunit;
namespace Microsoft.Templates.Core.Test.Extensions
{
[Trait("ExecutionSet", "Minimum")]
public class StringExtensionsTests
{
[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData(null)]
[InlineData("||")]
[InlineData("|")]
public void GetMultiValue_NoValue_ShouldReturnEmptyArray(string value)
{
var expected = Array.Empty<string>();
var actual = value.GetMultiValue();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData("One|", new string[] { "One" })]
[InlineData("One|Two", new string[] { "One", "Two" })]
[InlineData("One Two|", new string[] { "One Two" })]
[InlineData("One|Two Three", new string[] { "One", "Two Three" })]
[InlineData("One Two|Three", new string[] { "One Two", "Three" })]
[InlineData("One|Two||Three", new string[] { "One", "Two", "Three" })]
public void GetMultiValue_HasValue_ShouldReturnExpected(string value, string[] expected)
{
var actual = value.GetMultiValue();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData("| ")]
[InlineData("One| ")]
[InlineData("One |Two")]
[InlineData(" One|Two")]
[InlineData(" One|Two")]
[InlineData("One |Two")]
[InlineData(" One Two|")]
[InlineData("One Two |")]
[InlineData("One|Two|| Three")]
[InlineData("One|Two| |Three")]
[InlineData("One|Two||Three ")]
[InlineData("One| One Two||Three")]
[InlineData("One|One Two ||Three")]
[InlineData(" One Two|Three||Four")]
[InlineData("One Two |Three||Four")]
[InlineData("One|Two|| Three Four")]
[InlineData("One|Two||Three Four ")]
public void GetMultiValue_ValueContainsTrailingSpaces_ShouldThrowInvalidDataException(string value)
{
Assert.Throws<InvalidDataException>(() => { value.GetMultiValue(); });
}
[Theory]
[InlineData("One|Two")]
[InlineData("|One|Two|")]
[InlineData("One||Two|Three")]
[InlineData("One||Two Three|Four")]
[InlineData("One||Two Three")]
[InlineData("One Two||Two Three")]
public void IsMultiValue_IfSeveralValues_ShouldReturnTrue(string value)
{
var actual = value.IsMultiValue();
Assert.True(actual);
}
[Theory]
[InlineData(" One")]
[InlineData("One ")]
[InlineData(" One|")]
[InlineData("One |")]
[InlineData("One| ")]
[InlineData("One| Two")]
[InlineData("One|Two ")]
[InlineData(" |One|Two|")]
[InlineData(" |One|Two Three|")]
[InlineData(" |One|Two Three|Four")]
[InlineData("|One|Two Three |Four")]
[InlineData("|One|Two Three|Four ")]
[InlineData("One| | Two|Three")]
public void IsMultiValue_ValueContainsTrailingSpaces_ShouldThrowInvalidDataException(string value)
{
Assert.Throws<InvalidDataException>(() => { value.IsMultiValue(); });
}
[Theory]
[InlineData(null)]
[InlineData("")]
[InlineData(" ")]
[InlineData("||")]
[InlineData("One")]
[InlineData("One|")]
public void IsMultiValue_SingleOrNoValue_ShouldReturnFalse(string value)
{
var actual = value.IsMultiValue();
Assert.False(actual);
}
[Theory]
[InlineData("hello this is a statement", 0)]
[InlineData(" hello this is a statement", 1)]
[InlineData(" hello this is a statement", 3)]
public void GetLeadingTrivia_ShouldCountInitialWhitespacesCorrectly(string value, int expected)
{
var actual = value.GetLeadingTrivia();
Assert.Equal(expected, actual);
}
[Theory]
[InlineData("hello this is a statement", 0, "hello this is a statement")]
[InlineData("hello this is a statement", 1, " hello this is a statement")]
[InlineData("hello this is a statement", 3, " hello this is a statement")]
public void WithLeadingTrivia_Should(string value, int triviaCount, string expected)
{
var actual = value.WithLeadingTrivia(triviaCount);
Assert.Equal(expected, actual);
}
}
}

Просмотреть файл

@ -0,0 +1,89 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Templates.Core.Extensions;
using Xunit;
namespace Microsoft.Templates.Core.Test.Extensions
{
[Trait("ExecutionSet", "Minimum")]
public class TemplateTypeExtensionsTests
{
private const int PROJECT = 0;
private const int PAGE = 1;
private const int FEATURE = 2;
private const int SERVICE = 3;
private const int TESTING = 4;
private const int COMPOSITION = 5;
private const int UNSPECIFIED = 6;
[Theory]
[InlineData(PAGE)]
[InlineData(FEATURE)]
[InlineData(SERVICE)]
[InlineData(TESTING)]
public void IsItemTemplate_ShouldBeTrue(int templateTypeId)
{
TemplateType templateType = (TemplateType)templateTypeId;
var actual = templateType.IsItemTemplate();
Assert.True(actual);
}
[Theory]
[InlineData(PROJECT)]
[InlineData(COMPOSITION)]
[InlineData(UNSPECIFIED)]
public void IsItemTemplate_ShouldBeFalse(int templateTypeId)
{
TemplateType templateType = (TemplateType)templateTypeId;
var actual = templateType.IsItemTemplate();
Assert.False(actual);
}
private const int ADDPAGE = 1;
private const int ADDFEATURE = 2;
private const int ADDSERVICE = 3;
private const int ADDTESTING = 4;
[Theory]
[InlineData(PAGE)]
[InlineData(FEATURE)]
[InlineData(SERVICE)]
[InlineData(TESTING)]
public void GetWizardType_ShouldNotBeNull(int templateTypeId)
{
TemplateType templateType = (TemplateType)templateTypeId;
var actual = templateType.GetWizardType();
Assert.NotNull(actual);
}
[Theory]
[InlineData(PAGE, ADDPAGE)]
[InlineData(FEATURE, ADDFEATURE)]
[InlineData(SERVICE, ADDSERVICE)]
[InlineData(TESTING, ADDTESTING)]
public void GetWizardType_IsItemTemplate_ShouldMatchAValidWizardType(int templateTypeId, int? wizardTypeId)
{
TemplateType templateType = (TemplateType)templateTypeId;
var actual = templateType.GetWizardType();
Assert.Equal(wizardTypeId, (int?)actual.Value);
}
[Theory]
[InlineData(PROJECT)]
[InlineData(COMPOSITION)]
[InlineData(UNSPECIFIED)]
public void GetWizardType_NotItemTemplate_ShouldReturnNull(int templateTypeId)
{
TemplateType templateType = (TemplateType)templateTypeId;
var actual = templateType.GetWizardType();
Assert.Null(actual);
}
}
}

Просмотреть файл

@ -0,0 +1,111 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using Xunit;
namespace Microsoft.Templates.Core.Test.Extensions
{
[Trait("ExecutionSet", "Minimum")]
public class VersionExtensionsTests
{
[Fact]
public void IsNull_IsNullVersion_ShouldReturnTrue()
{
Version factData = null;
var actual = factData.IsNull();
Assert.True(actual);
}
[Fact]
public void IsNull_NotNullVersion_ShouldReturnFalse()
{
Version factData = new Version();
var actual = factData.IsNull();
Assert.False(actual);
}
[Fact]
public void IsZero_IsNullVersion_ShouldReturnFalse()
{
Version factData = null;
var actual = factData.IsZero();
Assert.False(actual);
}
[Theory]
[MemberData(nameof(ZeroData))]
public void IsZero_ZeroVersion_ShouldReturnTrue(Version version)
{
var actual = version.IsZero();
Assert.True(actual);
}
[Theory]
[MemberData(nameof(NonZeroVersionData))]
public void IsZero_NonZeroVersion_ShouldReturnFalse(Version version)
{
var actual = version.IsZero();
Assert.False(actual);
}
public static IEnumerable<object[]> ZeroData => new List<object[]>()
{
new object[]
{
new Version(),
},
new object[]
{
new Version("0.0"),
},
new object[]
{
new Version(0, 0),
},
new object[]
{
new Version(0, 0, 0),
},
new object[]
{
new Version(0, 0, 0, 0),
},
};
public static IEnumerable<object[]> NonZeroVersionData => new List<object[]>()
{
new object[]
{
new Version("1.0.0.0"),
},
new object[]
{
new Version("0.1.0.0"),
},
new object[]
{
new Version("0.0.1.0"),
},
new object[]
{
new Version(1, 0, 0, 0),
},
new object[]
{
new Version(0, 1, 0, 0),
},
new object[]
{
new Version(0, 0, 0, 1),
},
};
}
}

Просмотреть файл

@ -0,0 +1,135 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Xunit;
namespace Microsoft.Templates.Core.Test.Helpers.FsTests.Helpers
{
[SuppressMessage("Design", "CA1063:Implement IDisposable Correctly", Justification = "Testing purposes only")]
public class FSTestsFixture : IDisposable
{
public string LogFile { get; private set; }
public CultureInfo CultureInfo { get; }
public string TestPath { get; private set; }
private string folderPath;
public FSTestsFixture()
{
CultureInfo = new CultureInfo("en-US");
TestPath = Path.Combine(Environment.CurrentDirectory, "TempTestData");
Directory.CreateDirectory(TestPath);
LogFile = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
Configuration.Current.LogFileFolderPath,
$"WTS_{Configuration.Current.Environment}_{DateTime.Now:yyyyMMdd}.log");
if (File.Exists(LogFile))
{
File.Delete(LogFile);
}
}
public static void CreateFolders(string testFolder, List<string> folderPaths)
{
var foldersWithAbsolutePath = folderPaths.Select(f => $"{testFolder}\\{f}").ToList();
foreach (string folder in foldersWithAbsolutePath)
{
Directory.CreateDirectory(folder);
}
}
public static void CreateFiles(string testFolder, List<string> filePaths, bool isReadOnly = false)
{
var filesWithAbsolutePath = filePaths.Select(f => $"{testFolder}\\{f}").ToList();
foreach (string file in filesWithAbsolutePath)
{
using var stream = File.Create(file);
if (isReadOnly)
{
var fileInfo = new FileInfo(file)
{
IsReadOnly = isReadOnly,
};
}
}
}
public string CreateTempFolderForTest(string folderName)
{
folderPath = $"{TestPath}\\{folderName}";
Directory.CreateDirectory(folderPath);
return folderPath;
}
public static void DeleteTempFolderForTest(string folderPath)
{
if (Directory.Exists(folderPath))
{
foreach (var file in Directory.GetFiles(folderPath))
{
_ = new FileInfo(file)
{
IsReadOnly = false,
};
}
Directory.Delete(folderPath, true);
}
}
private bool CheckLoggingDataIsExpected(DateTime logDate, string errorLevel, string errorMessage)
{
// Sample of Logging line: [2021-06-07 20:51:30.557]... Warning Error creating folder 'C:\...\bin\Debug\netcoreapp3.1\TestData\EnsureFolderExists\Test_EnsureFolderExists': ..... because a file or directory with the same name already exists.
var logFileLines = File.ReadAllText(LogFile);
var errorDateFormat = $"{logDate:yyyy\\-MM\\-dd}";
var errorMatchPattern = $"^\\[({errorDateFormat}.*)({errorLevel}).*({errorMessage})";
var errorRegex = new Regex(errorMatchPattern, RegexOptions.Compiled | RegexOptions.Multiline);
return errorRegex.IsMatch(logFileLines);
}
public bool IsErrorMessageInLogFile(DateTime logDate, string errorLevel, string errorMessage)
{
if (File.Exists(LogFile))
{
var lastModifiedWriteTime = File.GetLastWriteTime(LogFile);
var timeSinceLastEdit = logDate - lastModifiedWriteTime;
if (timeSinceLastEdit.Seconds < 30)
{
return CheckLoggingDataIsExpected(logDate, errorLevel, errorMessage);
}
}
return false;
}
[SuppressMessage("Usage", "CA1816:Dispose methods should call SuppressFinalize", Justification = "Testing purposes only")]
public void Dispose()
{
if (Directory.Exists(TestPath))
{
Directory.Delete(TestPath, true);
}
}
}
[SuppressMessage("StyleCop", "SA1402", Justification = "This class does not have implementation")]
[CollectionDefinition("Unit Test Logs")]
public class LogCollection : ICollectionFixture<FSTestsFixture>
{
}
}

Просмотреть файл

@ -0,0 +1,67 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.IO;
using Microsoft.Templates.Core.Helpers;
using Xunit;
namespace Microsoft.Templates.Core.Test.Helpers
{
[Trait("ExecutionSet", "Minimum")]
public class FileHelpersTests
{
[Theory]
[InlineData("")]
[InlineData(" ")]
[InlineData(" ")]
[InlineData(null)]
public void GetFileContent_EmptyFilePath_ShouldReturnEmpty(string sourceFile)
{
var actual = FileHelper.GetFileContent(sourceFile);
Assert.Empty(actual);
}
[Theory]
[InlineData("TestData\\TestProject")]
[InlineData("TestData\\TestProject\\TestNotExisting.csproj")]
public void GetFileContent_WrongFilePath_ShouldReturnEmpty(string file)
{
var sourceFile = Path.Combine(Environment.CurrentDirectory, file);
var actual = FileHelper.GetFileContent(sourceFile);
Assert.Empty(actual);
}
[Fact]
public void GetFileContent_FileExists_ShouldReturnsCorrectly()
{
var sourceFile = Path.Combine(Environment.CurrentDirectory, "TestData\\TestProject\\Test.csproj");
var actual = FileHelper.GetFileContent(sourceFile);
Assert.NotEmpty(actual);
}
[Fact]
public void GetFileContent_WithFileOpened_ShouldReturnEmpty()
{
var sourceFile = Path.Combine(Environment.CurrentDirectory, "TestData\\TestProject\\EditingTest.csproj");
try
{
using var file = File.Create(sourceFile);
var actual = FileHelper.GetFileContent(sourceFile);
Assert.Empty(actual);
file.Close();
}
finally
{
File.Delete(sourceFile);
}
}
}
}

Просмотреть файл

@ -0,0 +1,103 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using Microsoft.Templates.Core.Helpers;
using Microsoft.Templates.Core.Test.Helpers.FsTests.Helpers;
using Xunit;
namespace Microsoft.Templates.Core.Test.Helpers.FsTests
{
[Collection("Unit Test Logs")]
[Trait("ExecutionSet", "Minimum")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1063:Implement IDisposable Correctly", Justification = "Testing purposes only")]
public class EnsureFileEditableTests : IDisposable
{
private readonly FSTestsFixture _fixture;
private readonly string _testFolder;
private DateTime _logDate;
private const string ErrorMessage = "Cannot remove readonly protection from file";
private const string ErrorLevel = "Warning";
public EnsureFileEditableTests(FSTestsFixture fixture)
{
_fixture = fixture;
Thread.CurrentThread.CurrentUICulture = fixture.CultureInfo;
_testFolder = _fixture.CreateTempFolderForTest("EnsureFolderExists");
}
[Fact]
public void EnsureFileEditable_FileIsReadOnly_ShouldChangeToReadOnly()
{
var testScenarioName = "FileIsReadOnly";
var fileToEdit = $"{_testFolder}\\{testScenarioName}";
try
{
FSTestsFixture.CreateFiles(_testFolder, new List<string> { testScenarioName }, true);
Fs.EnsureFileEditable(fileToEdit);
var newFileInfo = new FileInfo(fileToEdit);
Assert.False(newFileInfo.IsReadOnly);
}
finally
{
_ = new FileInfo(fileToEdit)
{
IsReadOnly = false,
};
}
}
[Theory]
[InlineData("")]
[InlineData(null)]
public void EnsureFileEditable_FilePathNullOrEmpty_ShouldLogError(string filePath)
{
_logDate = DateTime.Now;
Fs.EnsureFileEditable(filePath);
Assert.True(_fixture.IsErrorMessageInLogFile(_logDate, ErrorLevel, ErrorMessage));
}
[Fact]
public void EnsureFileEditable_FileDoesNotExist_ShouldLogError()
{
var testScenarioName = "FileDoesNotExist";
string filePath = $"{_testFolder}\\{testScenarioName}";
_logDate = DateTime.Now;
Fs.EnsureFileEditable(filePath);
Assert.True(_fixture.IsErrorMessageInLogFile(_logDate, ErrorLevel, ErrorMessage));
}
[Fact]
public void EnsureFileEditable_FileIsNotReadOnly_ShouldNotModifyIsReadOnly()
{
var testScenarioName = "FileIsNotReadOnly";
string filePath = $"{_testFolder}\\{testScenarioName}";
FSTestsFixture.CreateFiles(_testFolder, new List<string> { testScenarioName });
var originalFileInfo = new FileInfo(filePath);
Fs.EnsureFileEditable(filePath);
var newFileInfo = new FileInfo(filePath);
Assert.False(originalFileInfo.IsReadOnly);
Assert.False(newFileInfo.IsReadOnly);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA1816:Dispose methods should call SuppressFinalize", Justification = "Testing purposes only")]
public void Dispose()
{
FSTestsFixture.DeleteTempFolderForTest(_testFolder);
}
}
}

Просмотреть файл

@ -0,0 +1,95 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using Microsoft.Templates.Core.Helpers;
using Microsoft.Templates.Core.Test.Helpers.FsTests.Helpers;
using Xunit;
namespace Microsoft.Templates.Core.Test.Helpers.FsTests
{
[Collection("Unit Test Logs")]
[Trait("ExecutionSet", "Minimum")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1063:Implement IDisposable Correctly", Justification = "Testing purposes only")]
public class EnsureFolderExistsTests : IDisposable
{
private readonly FSTestsFixture _fixture;
private readonly string _testFolder;
private DateTime _logDate;
private const string ErrorMessage = "Error creating folder";
private const string ErrorLevel = "Warning";
public EnsureFolderExistsTests(FSTestsFixture fixture)
{
_fixture = fixture;
Thread.CurrentThread.CurrentUICulture = fixture.CultureInfo;
_testFolder = _fixture.CreateTempFolderForTest("EnsureFolderExists");
}
[Fact]
public void EnsureFolderExists_DirectoryDoesNotExists_ShouldCreateDirectory()
{
var testScenarioName = "DirectoryDoesNotExists";
var directoryToCreate = $"{_testFolder}\\{testScenarioName}";
var directoryExistsAtStart = Directory.Exists(directoryToCreate);
var totalOriginalDirectories = Directory.GetParent(directoryToCreate).GetDirectories().Length;
Fs.EnsureFolderExists(directoryToCreate);
var totalNewDirectories = Directory.GetParent(directoryToCreate).GetDirectories().Length;
Assert.True(totalNewDirectories > totalOriginalDirectories);
Assert.False(directoryExistsAtStart);
Assert.True(Directory.Exists(directoryToCreate));
}
[Fact]
public void EnsureFolderExists_DirectoryAlreadyExists_ShouldNotCreateDirectory()
{
var testScenarioName = "DirectoryAlreadyExists";
var directoryToCreate = $"{_testFolder}\\{testScenarioName}";
FSTestsFixture.CreateFolders(_testFolder, new List<string> { testScenarioName });
var directoryExistsAtStart = Directory.Exists(directoryToCreate);
var totalOriginalDirectories = Directory.GetParent(directoryToCreate).GetDirectories().Length;
Fs.EnsureFolderExists(directoryToCreate);
var totalNewDirectories = Directory.GetParent(directoryToCreate).GetDirectories().Length;
Assert.True(totalOriginalDirectories == totalNewDirectories);
Assert.True(directoryExistsAtStart);
Assert.True(Directory.Exists(directoryToCreate));
}
[Fact]
public void EnsureFolderExists_ErrorCreatingDirectory_ShouldLogException()
{
// To force an error creating a Directory
// we create a file with the name of the folder that we want to create
var testScenarioName = "ErrorCreatingDirectory";
var wrongDirectoryToCreate = $"{testScenarioName}\\{testScenarioName}.cs";
FSTestsFixture.CreateFolders(_testFolder, new List<string> { testScenarioName });
FSTestsFixture.CreateFiles(_testFolder, new List<string> { wrongDirectoryToCreate });
_logDate = DateTime.Now;
Fs.EnsureFolderExists($"{_testFolder}\\{wrongDirectoryToCreate}");
Assert.True(_fixture.IsErrorMessageInLogFile(_logDate, ErrorLevel, ErrorMessage));
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA1816:Dispose methods should call SuppressFinalize", Justification = "Testing purposes only")]
public void Dispose()
{
FSTestsFixture.DeleteTempFolderForTest(_testFolder);
}
}
}

Просмотреть файл

@ -0,0 +1,63 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Linq;
using Microsoft.Templates.Core.Helpers;
using Microsoft.Templates.Core.Test.Helpers.FsTests.Helpers;
using Xunit;
namespace Microsoft.Templates.Core.Test.Helpers.FsTests
{
[Collection("Unit Test Logs")]
[Trait("ExecutionSet", "Minimum")]
public class GetExistingFolderNamesTests
{
private readonly FSTestsFixture _fixture;
private readonly string _testFolder;
public GetExistingFolderNamesTests(FSTestsFixture fixture)
{
_fixture = fixture;
_testFolder = _fixture.CreateTempFolderForTest("GetExistingFolderNames");
}
[Fact]
public void GetExistingFolderNames_RootExists_ShouldReturnAllExpectedFolderNamesInAlphabeticalOrder()
{
var testScenarioName = "RootExists";
var directoryExists = $"{_testFolder}\\{testScenarioName}";
FSTestsFixture.CreateFolders(_testFolder, new List<string> { testScenarioName, $"{testScenarioName}\\One", $"{testScenarioName}\\Two", $"{testScenarioName}\\Three" });
var expected = new List<string>() { "One", "Three", "Two" };
var actual = Fs.GetExistingFolderNames(directoryExists);
Assert.Equal(3, actual.Count());
Assert.Equal(expected, actual);
}
[Theory]
[InlineData("")]
[InlineData(null)]
public void GetExistingFolderNames_RootDirectoryEmptyOrNull_ShouldReturnEmptyList(string rootDirectory)
{
var actual = Fs.GetExistingFolderNames(rootDirectory);
Assert.Empty(actual);
}
[Fact]
public void GetExistingFolderNames_RootDirectoryDoesNotExist_ShouldReturnEmptyList()
{
var testScenarioName = "RootDirectoryDoesNotExist";
var directoryDoesNotExist = $"{_testFolder}\\{testScenarioName}";
var actual = Fs.GetExistingFolderNames(directoryDoesNotExist);
Assert.Empty(actual);
}
}
}

Просмотреть файл

@ -0,0 +1,177 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using Microsoft.Templates.Core.Helpers;
using Microsoft.Templates.Core.Test.Helpers.FsTests.Helpers;
using Xunit;
namespace Microsoft.Templates.Core.Test.Helpers.FsTests
{
[Collection("Unit Test Logs")]
[Trait("ExecutionSet", "Minimum")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1063:Implement IDisposable Correctly", Justification = "Testing purposes only")]
public class SafeCopyFileTests : IDisposable
{
private readonly FSTestsFixture _fixture;
private readonly string _testFolder;
private readonly string _sourceFile;
private DateTime _logDate;
private const string ErrorMessage = "can't be copied to";
private const string ErrorLevel = "Warning";
public SafeCopyFileTests(FSTestsFixture fixture)
{
_fixture = fixture;
Thread.CurrentThread.CurrentUICulture = fixture.CultureInfo;
_sourceFile = $"TestData\\TestProject\\Test.csproj";
_testFolder = _fixture.CreateTempFolderForTest("SafeCopyFile");
}
[Fact]
public void SafeCopyFile_DestinationDirectoryDoesNotExist_ShouldCreateDirectory()
{
var testScenarioName = "DestinationDirectoryDoesNotExist";
var directoryToCreate = $"{_testFolder}\\{testScenarioName}";
var directoryExistsAtStart = Directory.Exists(directoryToCreate);
var totalOriginalDirectories = Directory.GetParent(directoryToCreate).GetDirectories().Length;
Fs.SafeCopyFile(_sourceFile, directoryToCreate, true);
var totalNewDirectories = Directory.GetParent(directoryToCreate).GetDirectories().Length;
var directoryHasBeenCreated = totalNewDirectories > totalOriginalDirectories;
Assert.False(directoryExistsAtStart);
Assert.True(directoryHasBeenCreated);
Assert.True(Directory.Exists(directoryToCreate));
}
[Fact]
public void SafeCopyFile_FileDoesNotExist_ShouldCreateNewFileWhileCopying()
{
var testScenarioName = "FileDoesNotExist";
var directoryToCreate = $"{_testFolder}\\{testScenarioName}";
FSTestsFixture.CreateFolders(_testFolder, new List<string>() { testScenarioName });
var expectedDestinationFile = Path.Combine(directoryToCreate, Path.GetFileName(_sourceFile));
var fileExistsAtStart = File.Exists(expectedDestinationFile);
var totalOriginalFiles = Directory.GetFiles(directoryToCreate).Length;
Fs.SafeCopyFile(_sourceFile, directoryToCreate, true);
var totalNewFiles = Directory.GetFiles(directoryToCreate).Length;
var fileHasBeenCreated = totalNewFiles > totalOriginalFiles;
Assert.False(fileExistsAtStart);
Assert.True(fileHasBeenCreated);
Assert.True(File.Exists(expectedDestinationFile));
}
[Fact]
public void SafeCopyFile_DestinationDirectoryAlreadyExists_ShouldNotCreateDirectory()
{
var testScenarioName = "DestinationDirectoryAlreadyExists";
var directoryToCopyFile = $"{_testFolder}\\{testScenarioName}";
FSTestsFixture.CreateFolders(_testFolder, new List<string>() { testScenarioName });
var totalOriginalDirectories = Directory.GetParent(directoryToCopyFile).GetDirectories().Length;
Fs.SafeCopyFile(_sourceFile, directoryToCopyFile, true);
var totalNewDirectories = Directory.GetParent(directoryToCopyFile).GetDirectories().Length;
var noDirectoryHasBeenCreated = totalOriginalDirectories == totalNewDirectories;
Assert.True(noDirectoryHasBeenCreated);
}
[Fact]
public void SafeCopyFile_FileAlreadyExists_ShouldNotCreateNewFileWhileCopying()
{
var testScenarioName = "FileAlreadyExists";
var directoryToCopyFile = $"{_testFolder}\\{testScenarioName}";
var totalOriginalFiles = Directory.GetParent(directoryToCopyFile).GetFiles().Length;
var expectedDestinationFile = Path.Combine(directoryToCopyFile, Path.GetFileName(_sourceFile));
var fileInfo = new FileInfo(expectedDestinationFile);
var originalLastModificationTime = fileInfo.LastWriteTime;
Fs.SafeCopyFile(_sourceFile, directoryToCopyFile, true);
var totalNewFiles = Directory.GetParent(directoryToCopyFile).GetFiles().Length;
var noFileHasBeenCreated = totalNewFiles == totalOriginalFiles;
fileInfo = new FileInfo(expectedDestinationFile);
var updatedLastModificationTime = fileInfo.LastWriteTime;
Assert.True(noFileHasBeenCreated);
Assert.NotEqual(originalLastModificationTime, updatedLastModificationTime);
}
[Theory]
[InlineData(null)]
[InlineData("")]
public void SafeCopyFile_SourceFileNullOrEmpty_ShouldLogException(string filePath)
{
var testScenarioName = "SourceFileNullOrEmpty";
var directoryToCopyFile = $"{_testFolder}\\{testScenarioName}";
_logDate = DateTime.Now;
Fs.SafeCopyFile(filePath, directoryToCopyFile, true);
Assert.True(_fixture.IsErrorMessageInLogFile(_logDate, ErrorLevel, ErrorMessage));
}
[Fact]
public void SafeCopyFile_CouldNotFindFile_ShouldLogException()
{
var testScenarioName = "CouldNotFindFile";
var directoryToCopyFile = $"{_testFolder}\\{testScenarioName}";
var sourceFileDoesNotExist = $"{_testFolder}\\FileDoNotExists.csproj";
_logDate = DateTime.Now;
Fs.SafeCopyFile(sourceFileDoesNotExist, directoryToCopyFile, true);
Assert.True(_fixture.IsErrorMessageInLogFile(_logDate, ErrorLevel, ErrorMessage));
}
[Fact]
public void SafeCopyFile_AccessToPathDenied_ShouldLogException()
{
// to force an exception while trying to copy a file. File without permissions instead of valid folder
var testScenarioName = "AccessToPathDenied";
var directoryToCopyFile = $"{_testFolder}\\{testScenarioName}";
var sourceFileDoesNotHavePermissions = Environment.CurrentDirectory;
_logDate = DateTime.Now;
Fs.SafeCopyFile(sourceFileDoesNotHavePermissions, directoryToCopyFile, true);
Assert.True(_fixture.IsErrorMessageInLogFile(_logDate, ErrorLevel, ErrorMessage));
}
[Fact]
public void SafeCopyFile_AccessToPathDenied_OvewriteFalse_ShouldLogException()
{
var testScenarioName = "AccessToPathDenied_OvewriteFalse";
var directoryToCopyFile = $"{_testFolder}\\{testScenarioName}";
var sourceFileDoesNotHavePermissions = Environment.CurrentDirectory;
_logDate = DateTime.Now;
Fs.SafeCopyFile(sourceFileDoesNotHavePermissions, directoryToCopyFile, false);
Assert.True(_fixture.IsErrorMessageInLogFile(_logDate, ErrorLevel, ErrorMessage));
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA1816:Dispose methods should call SuppressFinalize", Justification = "Testing purposes only")]
public void Dispose()
{
FSTestsFixture.DeleteTempFolderForTest(_testFolder);
}
}
}

Просмотреть файл

@ -0,0 +1,70 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Templates.Core.Helpers;
using Microsoft.Templates.Core.Test.Helpers.FsTests.Helpers;
using Xunit;
namespace Microsoft.Templates.Core.Test.Helpers.FsTests
{
[Collection("Unit Test Logs")]
[Trait("ExecutionSet", "Minimum")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1063:Implement IDisposable Correctly", Justification = "Testing purposes only")]
public class SafeDeleteDirectoryTests : IDisposable
{
private readonly FSTestsFixture _fixture;
private readonly string _testFolder;
public SafeDeleteDirectoryTests(FSTestsFixture fixture)
{
_fixture = fixture;
_testFolder = _fixture.CreateTempFolderForTest("SafeDeleteDirectory");
}
[Fact]
public void SafeDeleteDirectory_DirectoryExists_ShouldDeleteDirectory()
{
var testScenarioName = "DirectoryExists";
var directoryToCreate = $"{_testFolder}\\{testScenarioName}";
FSTestsFixture.CreateFolders(_testFolder, new List<string>() { testScenarioName });
var totalOriginalDirectories = Directory.GetParent(directoryToCreate).GetDirectories().Length;
Fs.SafeDeleteDirectory(directoryToCreate, false);
var totalNewDirectories = Directory.GetParent(directoryToCreate).GetDirectories().Length;
var directoryHasBeenDeleted = totalNewDirectories < totalOriginalDirectories;
Assert.True(directoryHasBeenDeleted);
}
[Theory]
[InlineData("")]
[InlineData(null)]
public void SafeDeleteDirectory_DirectoryPathIsNullOrEmpty_ShouldNotThrowException(string rootDir)
{
Fs.SafeDeleteDirectory(rootDir);
}
[Fact]
public void SafeDeleteDirectory_WrongFolder_ShouldNotThrowException()
{
var testScenarioName = "WrongFolder";
var wrongDirectoryToDelete = $"{_testFolder}\\{testScenarioName}";
Fs.SafeDeleteDirectory(wrongDirectoryToDelete, false);
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA1816:Dispose methods should call SuppressFinalize", Justification = "Testing purposes only")]
public void Dispose()
{
FSTestsFixture.DeleteTempFolderForTest(_testFolder);
}
}
}

Просмотреть файл

@ -0,0 +1,89 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using Microsoft.Templates.Core.Helpers;
using Microsoft.Templates.Core.Test.Helpers.FsTests.Helpers;
using Xunit;
namespace Microsoft.Templates.Core.Test.Helpers.FsTests
{
[Collection("Unit Test Logs")]
[Trait("ExecutionSet", "Minimum")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1063:Implement IDisposable Correctly", Justification = "Testing purposes only")]
public class SafeDeleteFileTests : IDisposable
{
private readonly FSTestsFixture _fixture;
private readonly string _testFolder;
private DateTime _logDate;
private const string ErrorMessage = "can't be deleted";
private const string ErrorLevel = "Warning";
public SafeDeleteFileTests(FSTestsFixture fixture)
{
_fixture = fixture;
Thread.CurrentThread.CurrentUICulture = fixture.CultureInfo;
_testFolder = _fixture.CreateTempFolderForTest("SafeDeleteFile");
}
[Fact]
public void SafeDeleteFile_ExistingFile_ShouldHaveDeletedFile()
{
var testScenarioName = "ExistingFile";
var directoryToCreate = $"{_testFolder}\\{testScenarioName}";
var fileToDelete = $"{directoryToCreate}\\{testScenarioName}.csproj";
FSTestsFixture.CreateFolders(_testFolder, new List<string>() { testScenarioName });
FSTestsFixture.CreateFiles(_testFolder, new List<string>() { $"{testScenarioName}\\{testScenarioName}.csproj" });
var fileExistsBefore = File.Exists(fileToDelete);
Fs.SafeDeleteFile(fileToDelete);
Assert.True(fileExistsBefore);
Assert.False(File.Exists(fileToDelete));
}
[Theory]
[InlineData("")]
[InlineData(null)]
public void SafeDeleteFile_PathNotFound_ShouldNotThrowException(string filePath)
{
Fs.SafeDeleteFile(filePath);
}
[Fact]
public void SafeDeleteFile_NoPermissions_ShouldHandleException()
{
var testScenarioName = "NoPermissions";
var directoryToCreate = $"{_testFolder}\\{testScenarioName}";
var fileToDelete = $"{directoryToCreate}\\{testScenarioName}.csproj";
try
{
FSTestsFixture.CreateFolders(_testFolder, new List<string>() { testScenarioName });
FSTestsFixture.CreateFiles(_testFolder, new List<string>() { $"{testScenarioName}\\{testScenarioName}.csproj" }, true);
_logDate = DateTime.Now;
Fs.SafeDeleteFile(fileToDelete);
Assert.True(_fixture.IsErrorMessageInLogFile(_logDate, ErrorLevel, ErrorMessage));
}
finally
{
_ = new FileInfo(fileToDelete)
{
IsReadOnly = false,
};
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA1816:Dispose methods should call SuppressFinalize", Justification = "Testing purposes only")]
public void Dispose()
{
FSTestsFixture.DeleteTempFolderForTest(_testFolder);
}
}
}

Просмотреть файл

@ -0,0 +1,159 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using Microsoft.Templates.Core.Helpers;
using Microsoft.Templates.Core.Test.Helpers.FsTests.Helpers;
using Xunit;
namespace Microsoft.Templates.Core.Test.Helpers.FsTests
{
[Collection("Unit Test Logs")]
[Trait("ExecutionSet", "Minimum")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1063:Implement IDisposable Correctly", Justification = "Testing purposes only")]
public class SafeMoveFileTests : IDisposable
{
private readonly FSTestsFixture _fixture;
private readonly string _testFolder;
private DateTime _logDate;
private const string ErrorMessage = "can't be moved to";
private const string ErrorLevel = "Warning";
public SafeMoveFileTests(FSTestsFixture fixture)
{
_fixture = fixture;
Thread.CurrentThread.CurrentUICulture = fixture.CultureInfo;
_testFolder = _fixture.CreateTempFolderForTest("SafeMoveFile");
}
[Fact]
public void SafeMoveFile_ValidData_ShouldMove()
{
var testScenarioName = "ValidData";
var originalFile = $"{_testFolder}\\{testScenarioName}_Original.cs";
var movedFile = $"{_testFolder}\\{testScenarioName}_Moved.cs";
FSTestsFixture.CreateFiles(_testFolder, new List<string> { Path.GetFileName(originalFile) });
var originFolderTotalFiles = Directory.GetFiles(_testFolder).Length;
Fs.SafeMoveFile(originalFile, movedFile);
var destinationFolderTotalFiles = Directory.GetFiles(_testFolder).Length;
Assert.True(originFolderTotalFiles == destinationFolderTotalFiles);
Assert.False(File.Exists(originalFile));
Assert.True(File.Exists(movedFile));
}
[Theory]
[InlineData("", "anything")]
[InlineData(null, "anything")]
public void SafeMoveFile_OriginFileDoesNotExist_JustReturns(string filePath, string newfilePath)
{
Fs.SafeMoveFile(filePath, newfilePath);
}
[Fact]
public void SafeMoveFile_DestFileExists_Overwrite_MovesFileSuccessfully()
{
var testScenarioName = "DestFileExists_Overwrite";
var originalFile = $"{_testFolder}\\{testScenarioName}_Original.cs";
var movedFile = $"{_testFolder}\\{testScenarioName}_Moved.cs";
FSTestsFixture.CreateFiles(_testFolder, new List<string> { Path.GetFileName(originalFile), Path.GetFileName(movedFile) });
var originFolderTotalFiles = Directory.GetFiles(_testFolder).Length;
Fs.SafeMoveFile(originalFile, movedFile);
var destinationFolderTotalFiles = Directory.GetFiles(_testFolder).Length;
Assert.True(originFolderTotalFiles > destinationFolderTotalFiles);
Assert.False(File.Exists(originalFile));
Assert.True(File.Exists(movedFile));
}
[Fact]
public void SafeMoveFile_DestFileExists_NoOverwrite_JustReturns()
{
var testScenarioName = "DestFileExists_NoOverwrite";
var originalFile = $"{_testFolder}\\{testScenarioName}_Original.cs";
var movedFile = $"{_testFolder}\\{testScenarioName}_Moved.cs";
FSTestsFixture.CreateFiles(_testFolder, new List<string> { Path.GetFileName(originalFile), Path.GetFileName(movedFile) });
var originFolderTotalFiles = Directory.GetFiles(_testFolder).Length;
Fs.SafeMoveFile(originalFile, movedFile, false);
var destinationFolderTotalFiles = Directory.GetFiles(_testFolder).Length;
Assert.True(originFolderTotalFiles == destinationFolderTotalFiles);
Assert.True(File.Exists(originalFile));
Assert.True(File.Exists(movedFile));
}
[Fact]
public void SafeMoveFile_DestFileExists_Overwrite_NoPermissions_ShouldLogException()
{
var testScenarioName = "DestFileExists_Overwrite_NoPermissions";
var originalFile = $"{_testFolder}\\{testScenarioName}_Original.cs";
var movedFile = $"{_testFolder}\\{testScenarioName}_Moved.cs";
FSTestsFixture.CreateFiles(_testFolder, new List<string> { Path.GetFileName(originalFile), Path.GetFileName(movedFile) }, true);
try
{
_logDate = DateTime.Now;
Fs.SafeMoveFile(originalFile, movedFile);
Assert.True(_fixture.IsErrorMessageInLogFile(_logDate, ErrorLevel, ErrorMessage));
}
finally
{
_ = new FileInfo(movedFile)
{
IsReadOnly = false,
};
}
}
[Fact]
public void SafeMoveFile_DestFileExists_Overwrite_NoPermissions_NoWarnOnFailure_ShouldNotLogException()
{
var testScenarioName = "DestFileExists_Overwrite_NoPermissions_NoWarnOnFailure";
var originalFile = $"{_testFolder}\\{testScenarioName}_Original.cs";
var movedFile = $"{_testFolder}\\{testScenarioName}_Moved.cs";
FSTestsFixture.CreateFiles(_testFolder, new List<string> { Path.GetFileName(originalFile), Path.GetFileName(movedFile) }, true);
try
{
_logDate = DateTime.Now;
Fs.SafeMoveFile(originalFile, movedFile, true, false);
Assert.False(_fixture.IsErrorMessageInLogFile(_logDate, ErrorLevel, $"{Path.GetFileName(movedFile)} {ErrorMessage}"));
}
finally
{
_ = new FileInfo(movedFile)
{
IsReadOnly = false,
};
}
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA1816:Dispose methods should call SuppressFinalize", Justification = "Testing purposes only")]
public void Dispose()
{
FSTestsFixture.DeleteTempFolderForTest(_testFolder);
}
}
}

Просмотреть файл

@ -0,0 +1,125 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using Microsoft.Templates.Core.Helpers;
using Microsoft.Templates.Core.Test.Helpers.FsTests.Helpers;
using Xunit;
namespace Microsoft.Templates.Core.Test.Helpers.FsTests
{
[Collection("Unit Test Logs")]
[Trait("ExecutionSet", "Minimum")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1063:Implement IDisposable Correctly", Justification = "Testing purposes only")]
public class SafeRenameDirectoryTests : IDisposable
{
private readonly FSTestsFixture _fixture;
private readonly string _testFolder;
private DateTime _logDate;
private const string ErrorMessage = "can't be renamed";
private const string ErrorLevel = "Warning";
public SafeRenameDirectoryTests(FSTestsFixture fixture)
{
_fixture = fixture;
Thread.CurrentThread.CurrentUICulture = fixture.CultureInfo;
_testFolder = _fixture.CreateTempFolderForTest("SafeRenameDirectory");
}
[Fact]
public void SafeRenameDirectory_ValidData_ShouldMoveDirectory()
{
var testScenarioName = "ValidData";
var originalDirectory = $"{_testFolder}\\{testScenarioName}_Original";
var renamedDirectory = $"{_testFolder}\\{testScenarioName}_Renamed";
FSTestsFixture.CreateFolders(_testFolder, new List<string> { $"{testScenarioName}_Original" });
var totalOriginalDirectories = Directory.GetParent(originalDirectory).GetDirectories().Length;
Fs.SafeRenameDirectory(originalDirectory, renamedDirectory);
var totalNewDirectories = Directory.GetParent(originalDirectory).GetDirectories().Length;
var sameNumberOfDirectories = totalNewDirectories == totalOriginalDirectories;
Assert.True(sameNumberOfDirectories);
var oldDirectoryHasBeenMovedToNewDirectory = Directory.Exists(renamedDirectory) && !Directory.Exists(originalDirectory);
Assert.True(oldDirectoryHasBeenMovedToNewDirectory);
}
[Theory]
[InlineData("", "anything")]
[InlineData(null, "anything")]
public void SafeRenameDirectory_DoesNotExist_ShouldNotThrowException(string rootDir, string newRootDir)
{
Fs.SafeRenameDirectory(rootDir, newRootDir);
}
[Fact]
public void SafeRenameDirectory_DirectoryAlreadyExists_ShouldLogException()
{
var testScenarioName = "ValidData";
var originalDirectory = $"{_testFolder}\\{testScenarioName}_Original";
var renamedDirectory = $"{_testFolder}\\{testScenarioName}_Renamed";
FSTestsFixture.CreateFolders(_testFolder, new List<string> { $"{testScenarioName}_Original", $"{testScenarioName}_Renamed" });
var totalOriginalDirectories = Directory.GetParent(originalDirectory).GetDirectories().Length;
_logDate = DateTime.Now;
Fs.SafeRenameDirectory(originalDirectory, renamedDirectory);
var totalNewDirectories = Directory.GetParent(originalDirectory).GetDirectories().Length;
var sameNumberOfDirectories = totalNewDirectories == totalOriginalDirectories;
Assert.True(sameNumberOfDirectories);
Assert.True(_fixture.IsErrorMessageInLogFile(_logDate, ErrorLevel, $"{testScenarioName}_Original {ErrorMessage}"));
}
[Fact]
public void SafeRenameDirectory_WrongDestinationFolder_ShouldLogException()
{
// to throw the exception we create a file with the same name we try to create the new directory
var testScenarioName = "WrongDestinationFolder";
var originalDirectory = $"{_testFolder}\\{testScenarioName}_Original";
var wrongDirectory = $"{_testFolder}\\{testScenarioName}_WrongFolder.cs";
FSTestsFixture.CreateFolders(_testFolder, new List<string> { $"{testScenarioName}_Original", $"{testScenarioName}_Renamed" });
FSTestsFixture.CreateFiles(_testFolder, new List<string> { $"{testScenarioName}_WrongFolder.cs" });
_logDate = DateTime.Now;
Fs.SafeRenameDirectory(originalDirectory, wrongDirectory);
Assert.True(_fixture.IsErrorMessageInLogFile(_logDate, ErrorLevel, $"{testScenarioName}_Original {ErrorMessage}"));
}
[Fact]
public void SafeRenameDirectory_WrongDestinationFolder_WarnOnFailureFalse_ShouldNotLogError()
{
// to throw the exception we create a file with the same name we try to create the new directory
var testScenarioName = "WrongDestinationFolder_WarnOnFailureFalse";
var originalDirectory = $"{_testFolder}\\{testScenarioName}_Original";
var wrongDirectory = $"{_testFolder}\\{testScenarioName}_WrongFolder.cs";
FSTestsFixture.CreateFolders(_testFolder, new List<string> { $"{testScenarioName}_Original", $"{testScenarioName}_Renamed" });
FSTestsFixture.CreateFiles(_testFolder, new List<string> { $"{testScenarioName}_WrongFolder.cs" });
_logDate = DateTime.Now;
Fs.SafeRenameDirectory(originalDirectory, wrongDirectory, false);
Assert.False(_fixture.IsErrorMessageInLogFile(_logDate, ErrorLevel, $"{testScenarioName}_Original {ErrorMessage}"));
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA1816:Dispose methods should call SuppressFinalize", Justification = "Testing purposes only")]
public void Dispose()
{
FSTestsFixture.DeleteTempFolderForTest(_testFolder);
}
}
}

Просмотреть файл

@ -127,7 +127,7 @@ namespace WtsPackagingTool
destinationDir = System.Environment.CurrentDirectory; destinationDir = System.Environment.CurrentDirectory;
} }
Fs.EnsureFolder(destinationDir); Fs.EnsureFolderExists(destinationDir);
output.WriteCommandHeader($"Extracting {inputFile} to {destinationDir}..."); output.WriteCommandHeader($"Extracting {inputFile} to {destinationDir}...");
await templatePackage.ExtractAsync(inputFile, destinationDir).ConfigureAwait(false); await templatePackage.ExtractAsync(inputFile, destinationDir).ConfigureAwait(false);
@ -306,7 +306,7 @@ namespace WtsPackagingTool
} }
else else
{ {
Fs.EnsureFolder(resultDir); Fs.EnsureFolderExists(resultDir);
} }
return resultDir; return resultDir;

Просмотреть файл

@ -106,7 +106,7 @@ namespace WtsPackagingTool
if (package != null) if (package != null)
{ {
Fs.EnsureFolder(options.Destination); Fs.EnsureFolderExists(options.Destination);
var result = RemoteSource.DownloadCdnElement(Environments.CdnUrls[options.Env], package.Name, options.Destination); var result = RemoteSource.DownloadCdnElement(Environments.CdnUrls[options.Env], package.Name, options.Destination);
output.WriteLine(); output.WriteLine();