refactor:将每个测试方法改为相互独立
原因是: 1. 相互独立的单元测试,有助于debug问题, 2. 不需要考虑执行顺序,额外的运行环境等,更加简单。 做的工作是: 1. 去掉了顺序执行,这有助于并发调用,减少测试时间 2. 去掉了测试方法中共享的实例
This commit is contained in:
parent
fc6c7bf8d2
commit
78d9e68fea
13 changed files with 265 additions and 166 deletions
|
@ -6,4 +6,8 @@
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="SharpZipLib" Version="1.4.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -465,7 +465,7 @@ public class Dir(string path, List<AFileOrDir>? children = null, NextOpType? nex
|
||||||
{
|
{
|
||||||
var ldir = this;
|
var ldir = this;
|
||||||
var rdir = other;
|
var rdir = other;
|
||||||
Dir? cDir = new Dir(rdir.FormatedPath);
|
Dir? cDir = new(rdir.FormatedPath);
|
||||||
//分别对文件和文件夹分组
|
//分别对文件和文件夹分组
|
||||||
List<File> lFiles = [];
|
List<File> lFiles = [];
|
||||||
List<File> rFiles = [];
|
List<File> rFiles = [];
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Security.AccessControl;
|
using System.Security.AccessControl;
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
|
using ICSharpCode.SharpZipLib.Zip;
|
||||||
using Microsoft.VisualBasic;
|
using Microsoft.VisualBasic;
|
||||||
|
|
||||||
namespace Common;
|
namespace Common;
|
||||||
|
@ -26,7 +27,8 @@ public abstract class FileDirOpStra
|
||||||
/// 文件目录打包
|
/// 文件目录打包
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="dstRootPath"></param>
|
/// <param name="dstRootPath"></param>
|
||||||
public class FileDirOpForPack(string srcRootPath, string dstRootPath) : FileDirOpStra
|
public class FileDirOpForPack(string srcRootPath, string dstRootPath, string syncId = "")
|
||||||
|
: FileDirOpStra
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 目标根目录
|
/// 目标根目录
|
||||||
|
@ -38,12 +40,78 @@ public class FileDirOpForPack(string srcRootPath, string dstRootPath) : FileDirO
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly string SrcRootPath = srcRootPath;
|
public readonly string SrcRootPath = srcRootPath;
|
||||||
|
|
||||||
|
public readonly string SyncId = string.IsNullOrEmpty(syncId)
|
||||||
|
? Guid.NewGuid().ToString()
|
||||||
|
: syncId;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 最终完成时的压缩
|
/// 最终完成时的压缩
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void FinallyCompress()
|
public void FinallyCompress()
|
||||||
{
|
{
|
||||||
var x = DstRootPath;
|
static List<string> GetFilesResus(string dirPath)
|
||||||
|
{
|
||||||
|
var files = new List<string>();
|
||||||
|
foreach (var file in Directory.GetFiles(dirPath))
|
||||||
|
{
|
||||||
|
files.Add(file);
|
||||||
|
}
|
||||||
|
foreach (var dir in Directory.GetDirectories(dirPath))
|
||||||
|
{
|
||||||
|
foreach (var file in GetFilesResus(dir))
|
||||||
|
{
|
||||||
|
files.Add(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
var fileNames = GetFilesResus(SrcRootPath);
|
||||||
|
var OuptPutFile = Path.GetDirectoryName(DstRootPath) + $"/{SyncId}.zip";
|
||||||
|
using FileStream fsOut = new(OuptPutFile, FileMode.Create);
|
||||||
|
using ZipOutputStream zipStream = new(fsOut);
|
||||||
|
{
|
||||||
|
zipStream.SetLevel(9); // 设置压缩级别
|
||||||
|
zipStream.Password = "VSXsdf.123d7802zw@#4_"; // 设置密码
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
|
||||||
|
foreach (string file in fileNames)
|
||||||
|
{
|
||||||
|
// Using GetFileName makes the result compatible with XP
|
||||||
|
// as the resulting path is not absolute.
|
||||||
|
var entry = new ZipEntry(file.Replace(SrcRootPath, ""));
|
||||||
|
|
||||||
|
// Setup the entry data as required.
|
||||||
|
|
||||||
|
// Crc and size are handled by the library for seakable streams
|
||||||
|
// so no need to do them here.
|
||||||
|
|
||||||
|
// Could also use the last write time or similar for the file.
|
||||||
|
//entry.DateTime = ;
|
||||||
|
entry.DateTime = System.IO.File.GetLastWriteTime(file);
|
||||||
|
zipStream.PutNextEntry(entry);
|
||||||
|
|
||||||
|
using (FileStream fs = System.IO.File.OpenRead(file))
|
||||||
|
{
|
||||||
|
// Using a fixed size buffer here makes no noticeable difference for output
|
||||||
|
// but keeps a lid on memory usage.
|
||||||
|
int sourceBytes;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
sourceBytes = fs.Read(buffer, 0, buffer.Length);
|
||||||
|
zipStream.Write(buffer, 0, sourceBytes);
|
||||||
|
} while (sourceBytes > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finish/Close arent needed strictly as the using statement does this automatically
|
||||||
|
|
||||||
|
// Finish is important to ensure trailing information for a Zip file is appended. Without this
|
||||||
|
// the created file would be invalid.
|
||||||
|
zipStream.Finish();
|
||||||
|
|
||||||
|
// Close is important to wrap things up and unlock the file.
|
||||||
|
zipStream.Close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -97,27 +165,70 @@ public class FileDirOpForPack(string srcRootPath, string dstRootPath) : FileDirO
|
||||||
this.FileCreate(absolutePath, mtime);
|
this.FileCreate(absolutePath, mtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void FileDel(string absolutePath)
|
public override void FileDel(string absolutePath) { }
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void DirDel(Dir dir, bool IsRecursion = true)
|
public override void DirDel(Dir dir, bool IsRecursion = true) { }
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FileDirOpForUnpack(string srcCompressedPath, string dstRootPath) : FileDirOpStra
|
public class FileDirOpForUnpack(string srcRootPath, string dstRootPath, string syncId)
|
||||||
|
: FileDirOpStra
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 解压缩,必须首先调用
|
/// 解压缩,必须首先调用
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void FirstUnComparess()
|
public void FirstUnComparess()
|
||||||
{
|
{
|
||||||
var x = SrcCompressedPath;
|
string zipFilePath = $"{SrcRootPath}/{SyncId}.zip";
|
||||||
|
|
||||||
|
using (ZipInputStream s = new ZipInputStream(System.IO.File.OpenRead(zipFilePath)))
|
||||||
|
{
|
||||||
|
s.Password = "VSXsdf.123d7802zw@#4_";
|
||||||
|
ZipEntry theEntry;
|
||||||
|
while ((theEntry = s.GetNextEntry()) != null)
|
||||||
|
{
|
||||||
|
Console.WriteLine(theEntry.Name);
|
||||||
|
|
||||||
|
string directoryName =
|
||||||
|
DstRootPath + $"/{SyncId}/" + Path.GetDirectoryName(theEntry.Name)
|
||||||
|
?? throw new NullReferenceException("无法得到父文件目录!");
|
||||||
|
string fileName = Path.GetFileName(theEntry.Name);
|
||||||
|
|
||||||
|
// create directory
|
||||||
|
if (directoryName.Length > 0)
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(directoryName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileName != String.Empty)
|
||||||
|
{
|
||||||
|
using (
|
||||||
|
FileStream streamWriter = System.IO.File.Create(
|
||||||
|
directoryName + "/" + fileName
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int size = 2048;
|
||||||
|
byte[] data = new byte[2048];
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
size = s.Read(data, 0, data.Length);
|
||||||
|
if (size > 0)
|
||||||
|
{
|
||||||
|
streamWriter.Write(data, 0, size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public readonly string SyncId = syncId;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 目标根目录
|
/// 目标根目录
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -126,7 +237,7 @@ public class FileDirOpForUnpack(string srcCompressedPath, string dstRootPath) :
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 源目录
|
/// 源目录
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly string SrcCompressedPath = srcCompressedPath;
|
public readonly string SrcRootPath = srcRootPath;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 最终完成时的压缩
|
/// 最终完成时的压缩
|
||||||
|
|
33
Server/LocalServer/Controllers/LocalServerController.cs
Normal file
33
Server/LocalServer/Controllers/LocalServerController.cs
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
using System.Text;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
|
namespace LocalServer.Controllers
|
||||||
|
{
|
||||||
|
public class LocalServerController(LocalSyncServerFactory factory) : ControllerBase
|
||||||
|
{
|
||||||
|
private readonly LocalSyncServerFactory Factory = factory;
|
||||||
|
|
||||||
|
[Route("/")]
|
||||||
|
public async Task WebsocketConnection(string Name)
|
||||||
|
{
|
||||||
|
if (HttpContext.WebSockets.IsWebSocketRequest)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
|
||||||
|
Factory.CreateLocalSyncServer(webSocket, Name);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
HttpContext.Response.Body = new MemoryStream(Encoding.UTF8.GetBytes(e.Message));
|
||||||
|
HttpContext.Response.StatusCode = StatusCodes.Status406NotAcceptable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//TODO 是否在本地记载同步日志?
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,33 +0,0 @@
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
|
|
||||||
namespace LocalServer.Controllers
|
|
||||||
{
|
|
||||||
[ApiController]
|
|
||||||
[Route("[controller]")]
|
|
||||||
public class WeatherForecastController : ControllerBase
|
|
||||||
{
|
|
||||||
private static readonly string[] Summaries = new[]
|
|
||||||
{
|
|
||||||
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
|
|
||||||
};
|
|
||||||
|
|
||||||
private readonly ILogger<WeatherForecastController> _logger;
|
|
||||||
|
|
||||||
public WeatherForecastController(ILogger<WeatherForecastController> logger)
|
|
||||||
{
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HttpGet(Name = "GetWeatherForecast")]
|
|
||||||
public IEnumerable<WeatherForecast> Get()
|
|
||||||
{
|
|
||||||
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
|
|
||||||
{
|
|
||||||
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
|
|
||||||
TemperatureC = Random.Shared.Next(-20, 55),
|
|
||||||
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
|
|
||||||
})
|
|
||||||
.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
19
Server/LocalServer/LocalSyncServer.cs
Normal file
19
Server/LocalServer/LocalSyncServer.cs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
using System.Net.WebSockets;
|
||||||
|
|
||||||
|
namespace LocalServer;
|
||||||
|
|
||||||
|
public class LocalSyncServer
|
||||||
|
{
|
||||||
|
public readonly WebSocket Socket;
|
||||||
|
public readonly string Name;
|
||||||
|
|
||||||
|
public readonly LocalSyncServerFactory Factory;
|
||||||
|
|
||||||
|
public LocalSyncServer(WebSocket socket, string name, LocalSyncServerFactory factory)
|
||||||
|
{
|
||||||
|
Socket = socket;
|
||||||
|
Name = name;
|
||||||
|
Factory = factory;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
22
Server/LocalServer/LocalSyncServerFactory.cs
Normal file
22
Server/LocalServer/LocalSyncServerFactory.cs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
using System.Net.WebSockets;
|
||||||
|
|
||||||
|
namespace LocalServer;
|
||||||
|
|
||||||
|
public class LocalSyncServerFactory
|
||||||
|
{
|
||||||
|
public void CreateLocalSyncServer(WebSocket socket, string name)
|
||||||
|
{
|
||||||
|
if (Servers.Select(x => x.Name == name).Any())
|
||||||
|
{
|
||||||
|
throw new Exception("there already is a server with that name is Runing!");
|
||||||
|
}
|
||||||
|
Servers.Add(new LocalSyncServer(socket, name, this));
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly List<LocalSyncServer> Servers = [];
|
||||||
|
|
||||||
|
public void RemoveLocalSyncServer(LocalSyncServer server)
|
||||||
|
{
|
||||||
|
Servers.Remove(server);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,34 +1,26 @@
|
||||||
|
using LocalServer;
|
||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
namespace LocalServer
|
// Add services to the container.
|
||||||
|
|
||||||
|
builder.Services.AddControllers();
|
||||||
|
|
||||||
|
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
||||||
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
|
builder.Services.AddSwaggerGen();
|
||||||
|
builder.Services.AddSingleton<LocalSyncServerFactory>();
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
|
||||||
|
// Configure the HTTP request pipeline.
|
||||||
|
if (app.Environment.IsDevelopment())
|
||||||
{
|
{
|
||||||
public class Program
|
app.UseSwagger();
|
||||||
{
|
app.UseSwaggerUI();
|
||||||
public static void Main(string[] args)
|
|
||||||
{
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
|
||||||
|
|
||||||
// Add services to the container.
|
|
||||||
|
|
||||||
builder.Services.AddControllers();
|
|
||||||
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
|
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
|
||||||
builder.Services.AddSwaggerGen();
|
|
||||||
|
|
||||||
var app = builder.Build();
|
|
||||||
|
|
||||||
// Configure the HTTP request pipeline.
|
|
||||||
if (app.Environment.IsDevelopment())
|
|
||||||
{
|
|
||||||
app.UseSwagger();
|
|
||||||
app.UseSwaggerUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
app.UseAuthorization();
|
|
||||||
|
|
||||||
|
|
||||||
app.MapControllers();
|
|
||||||
|
|
||||||
app.Run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
app.UseWebSockets();
|
||||||
|
app.UseAuthorization();
|
||||||
|
|
||||||
|
app.MapControllers();
|
||||||
|
|
||||||
|
app.Run();
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
namespace LocalServer
|
|
||||||
{
|
|
||||||
public class WeatherForecast
|
|
||||||
{
|
|
||||||
public DateOnly Date { get; set; }
|
|
||||||
|
|
||||||
public int TemperatureC { get; set; }
|
|
||||||
|
|
||||||
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
|
|
||||||
|
|
||||||
public string? Summary { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,31 +1,24 @@
|
||||||
using Common;
|
using Common;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
/*using Newtonsoft.Json;*/
|
/*using Newtonsoft.Json;*/
|
||||||
using XUnit.Project.Attributes;
|
|
||||||
|
|
||||||
namespace ServerTest;
|
namespace ServerTest;
|
||||||
|
|
||||||
/// <summary>
|
public class DirFileOpTest : IDisposable
|
||||||
/// xUnit将会对每个测试方法创建一个测试上下文,IClassFixture可以用来创建类中共享测试上下文,
|
|
||||||
///
|
|
||||||
/// XUnit 的测试方法不是按照顺序执行,所以注意对象状态
|
|
||||||
///
|
|
||||||
/// 一般单元测试,每个测试函数应当是独立的,不让它们按照顺序执行,在一般情况下是最好的做法,参考
|
|
||||||
/// https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-best-practices
|
|
||||||
/// 目前涉及到一些文件的同步,所以按照顺序执行相对较好,这使用了xUnit的方法使它们按照顺序执行
|
|
||||||
/// </summary>
|
|
||||||
///
|
|
||||||
[TestCaseOrderer(
|
|
||||||
ordererTypeName: "XUnit.Project.Orderers.PriorityOrderer",
|
|
||||||
ordererAssemblyName: "ServerTest"
|
|
||||||
)]
|
|
||||||
public class DirFileOpTest(FilesSeed filesSeed) : IClassFixture<FilesSeed>
|
|
||||||
{
|
{
|
||||||
private readonly FilesSeed filesSeed = filesSeed;
|
private readonly FilesSeed filesSeed = new();
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
//filesSeed.Dispose();
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 测试文件目录写入和提取
|
/// 测试文件目录写入和提取
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Fact, TestPriority(0)]
|
[Fact]
|
||||||
public void FileDirWriteExtract()
|
public void FileDirWriteExtract()
|
||||||
{
|
{
|
||||||
filesSeed.NewDir.WriteByThisInfo(filesSeed.fileDirOp);
|
filesSeed.NewDir.WriteByThisInfo(filesSeed.fileDirOp);
|
||||||
|
@ -41,11 +34,10 @@ public class DirFileOpTest(FilesSeed filesSeed) : IClassFixture<FilesSeed>
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 测试文件差异比较
|
/// 测试文件差异比较
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Fact, TestPriority(1)]
|
[Fact]
|
||||||
public void FileDirDiff()
|
public void FileDirDiff()
|
||||||
{
|
{
|
||||||
var cDDir = filesSeed.NewDir.Diff(filesSeed.OldDir);
|
var cDDir = filesSeed.NewDir.Diff(filesSeed.OldDir);
|
||||||
|
|
||||||
// Console.WriteLine("################################");
|
// Console.WriteLine("################################");
|
||||||
// Console.WriteLine(cDDir.Children.Count);
|
// Console.WriteLine(cDDir.Children.Count);
|
||||||
//Assert.True(IsSuccess);
|
//Assert.True(IsSuccess);
|
||||||
|
@ -57,9 +49,10 @@ public class DirFileOpTest(FilesSeed filesSeed) : IClassFixture<FilesSeed>
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 测试同步是否成功
|
/// 测试同步是否成功
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Fact, TestPriority(2)]
|
[Fact]
|
||||||
public void SyncFileDir()
|
public void SyncFileDir()
|
||||||
{
|
{
|
||||||
|
filesSeed.OldDir.WriteByThisInfo(filesSeed.fileDirOp);
|
||||||
filesSeed.OldDir.CombineJustDirFile(filesSeed.fileDirOp, filesSeed.DiffDir);
|
filesSeed.OldDir.CombineJustDirFile(filesSeed.fileDirOp, filesSeed.DiffDir);
|
||||||
Dir oldSync = new(filesSeed.OldDir.FormatedPath);
|
Dir oldSync = new(filesSeed.OldDir.FormatedPath);
|
||||||
oldSync.ExtractInfo();
|
oldSync.ExtractInfo();
|
||||||
|
@ -70,7 +63,7 @@ public class DirFileOpTest(FilesSeed filesSeed) : IClassFixture<FilesSeed>
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 测试文件合并
|
/// 测试文件合并
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Fact, TestPriority(3)]
|
[Fact]
|
||||||
public void DirsCombine()
|
public void DirsCombine()
|
||||||
{
|
{
|
||||||
filesSeed.OldDir.CombineJustObject(filesSeed.DiffDir);
|
filesSeed.OldDir.CombineJustObject(filesSeed.DiffDir);
|
||||||
|
@ -79,4 +72,19 @@ public class DirFileOpTest(FilesSeed filesSeed) : IClassFixture<FilesSeed>
|
||||||
// Console.WriteLine(filesSeed.OldDir.Path);
|
// Console.WriteLine(filesSeed.OldDir.Path);
|
||||||
Assert.True(filesSeed.OldDir.IsEqual(filesSeed.NewDir), "合并结果不一致!");
|
Assert.True(filesSeed.OldDir.IsEqual(filesSeed.NewDir), "合并结果不一致!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Tt()
|
||||||
|
{
|
||||||
|
filesSeed.NewDir.WriteByThisInfo(filesSeed.fileDirOp);
|
||||||
|
var c = new FileDirOpForPack(filesSeed.NewDir.FormatedPath, filesSeed.TestPath + "/");
|
||||||
|
c.FinallyCompress();
|
||||||
|
|
||||||
|
var d = new FileDirOpForUnpack(
|
||||||
|
filesSeed.TestPath + "/",
|
||||||
|
filesSeed.TestPath + "/",
|
||||||
|
c.SyncId
|
||||||
|
);
|
||||||
|
d.FirstUnComparess();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,7 +176,7 @@ public class FilesSeed : IDisposable
|
||||||
fileDirOp = new SimpleFileDirOp();
|
fileDirOp = new SimpleFileDirOp();
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly string TestPath = Path.Combine(Directory.GetCurrentDirectory(), "../../..");
|
public readonly string TestPath = Path.Combine(Directory.GetCurrentDirectory(), "../../..");
|
||||||
public Dir NewDir;
|
public Dir NewDir;
|
||||||
public Dir OldDir;
|
public Dir OldDir;
|
||||||
public Dir DiffDir;
|
public Dir DiffDir;
|
||||||
|
@ -184,8 +184,14 @@ public class FilesSeed : IDisposable
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Directory.Delete($"{TestPath}/OldDir", true);
|
if (Directory.Exists($"{TestPath}/OldDir"))
|
||||||
Directory.Delete($"{TestPath}/NewDir", true);
|
{
|
||||||
|
Directory.Delete($"{TestPath}/OldDir", true);
|
||||||
|
}
|
||||||
|
if (Directory.Exists($"{TestPath}/NewDir"))
|
||||||
|
{
|
||||||
|
Directory.Delete($"{TestPath}/NewDir", true);
|
||||||
|
}
|
||||||
Console.WriteLine("FilesSeed Dispose");
|
Console.WriteLine("FilesSeed Dispose");
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,41 +0,0 @@
|
||||||
using Xunit.Abstractions;
|
|
||||||
using Xunit.Sdk;
|
|
||||||
using XUnit.Project.Attributes;
|
|
||||||
|
|
||||||
namespace XUnit.Project.Orderers;
|
|
||||||
|
|
||||||
public class PriorityOrderer : ITestCaseOrderer
|
|
||||||
{
|
|
||||||
public IEnumerable<TTestCase> OrderTestCases<TTestCase>(
|
|
||||||
IEnumerable<TTestCase> testCases) where TTestCase : ITestCase
|
|
||||||
{
|
|
||||||
string assemblyName = typeof(TestPriorityAttribute).AssemblyQualifiedName!;
|
|
||||||
var sortedMethods = new SortedDictionary<int, List<TTestCase>>();
|
|
||||||
foreach (TTestCase testCase in testCases)
|
|
||||||
{
|
|
||||||
int priority = testCase.TestMethod.Method
|
|
||||||
.GetCustomAttributes(assemblyName)
|
|
||||||
.FirstOrDefault()
|
|
||||||
?.GetNamedArgument<int>(nameof(TestPriorityAttribute.Priority)) ?? 0;
|
|
||||||
|
|
||||||
GetOrCreate(sortedMethods, priority).Add(testCase);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (TTestCase testCase in
|
|
||||||
sortedMethods.Keys.SelectMany(
|
|
||||||
priority => sortedMethods[priority].OrderBy(
|
|
||||||
testCase => testCase.TestMethod.Method.Name)))
|
|
||||||
{
|
|
||||||
Console.WriteLine(testCase);
|
|
||||||
yield return testCase;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TValue GetOrCreate<TKey, TValue>(
|
|
||||||
IDictionary<TKey, TValue> dictionary, TKey key)
|
|
||||||
where TKey : struct
|
|
||||||
where TValue : new() =>
|
|
||||||
dictionary.TryGetValue(key, out TValue? result)
|
|
||||||
? result
|
|
||||||
: (dictionary[key] = new TValue());
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
namespace XUnit.Project.Attributes;
|
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
|
||||||
public class TestPriorityAttribute : Attribute
|
|
||||||
{
|
|
||||||
public int Priority { get; private set; }
|
|
||||||
|
|
||||||
public TestPriorityAttribute(int priority) => Priority = priority;
|
|
||||||
}
|
|
Loading…
Reference in a new issue