From 42fe455f66b527a2f1260c3c084c01017ffade06 Mon Sep 17 00:00:00 2001 From: IgnatSergeev Date: Thu, 30 Nov 2023 16:42:03 +0300 Subject: [PATCH 1/6] Finished --- .../Md5Calculator/CalculatorException.cs | 12 +++ C#/forSpbu/Md5Calculator/Md5Calculator.cs | 75 +++++++++++++++++++ C#/forSpbu/Md5Calculator/Md5Calculator.csproj | 11 +++ C#/forSpbu/Md5Calculator/Program.cs | 18 +++++ C#/forSpbu/forSpbu.sln | 27 ++++++- 5 files changed, 139 insertions(+), 4 deletions(-) create mode 100644 C#/forSpbu/Md5Calculator/CalculatorException.cs create mode 100644 C#/forSpbu/Md5Calculator/Md5Calculator.cs create mode 100644 C#/forSpbu/Md5Calculator/Md5Calculator.csproj create mode 100644 C#/forSpbu/Md5Calculator/Program.cs diff --git a/C#/forSpbu/Md5Calculator/CalculatorException.cs b/C#/forSpbu/Md5Calculator/CalculatorException.cs new file mode 100644 index 0000000..761ffc4 --- /dev/null +++ b/C#/forSpbu/Md5Calculator/CalculatorException.cs @@ -0,0 +1,12 @@ +namespace Md5Calculator; + +public class CalculatorException : ArgumentException +{ + public CalculatorException(string message) : base(message) + { + } + + public CalculatorException() + { + } +} \ No newline at end of file diff --git a/C#/forSpbu/Md5Calculator/Md5Calculator.cs b/C#/forSpbu/Md5Calculator/Md5Calculator.cs new file mode 100644 index 0000000..5595d1e --- /dev/null +++ b/C#/forSpbu/Md5Calculator/Md5Calculator.cs @@ -0,0 +1,75 @@ +namespace Md5Calculator; + +using System.Security.Cryptography; + +public static class Md5Calculator +{ + public static async Task ComputeAsync(string path) + { + if (!Directory.Exists(path) && !File.Exists(path)) + { + throw new CalculatorException("Path doesnt exist"); + } + + return !Directory.Exists(path) ? await ComputeFileAsync(path) : await ComputeDirAsync(path); + } + + public static byte[] Compute(string path) + { + if (!Directory.Exists(path) && !File.Exists(path)) + { + throw new CalculatorException("Path doesnt exist"); + } + + return !Directory.Exists(path) ? ComputeFile(path) : ComputeDir(path); + } + + + private static async Task ComputeDirAsync(string path) + { + Console.WriteLine("Async dir"); + Directory.GetFiles(path).Select(file => + { + Console.WriteLine(file); + return "asd"; + }); + + var fileTasks = Directory.GetFiles(path).Select(ComputeFileAsync); + + var dirTasks = Directory.GetDirectories(path).Select(ComputeDirAsync); + + var tasks = fileTasks.Concat(dirTasks) + .Append(new Task(() => ComputeString(Path.GetDirectoryName(path)!))) + .ToArray(); + await Task.WhenAll(tasks); + + var overallBytes = tasks.SelectMany(task => task.Result).ToArray(); + return MD5.HashData(overallBytes); + } + + private static byte[] ComputeDir(string path) + { + var fileBytes = Directory.GetFiles(path).SelectMany(ComputeFile); + + var dirBytes = Directory.GetDirectories(path).SelectMany(ComputeDir); + + var overallBytes = fileBytes.Concat(dirBytes).Concat(ComputeString(Path.GetDirectoryName(path)!)).ToArray(); + return MD5.HashData(overallBytes); + } + + private static async Task ComputeFileAsync(string path) + { + return await MD5.HashDataAsync(File.Open(path, FileMode.Open)); + } + + private static byte[] ComputeFile(string path) + { + return MD5.HashData(File.Open(path, FileMode.Open)); + } + + private static byte[] ComputeString(string @string) + { + var inputBytes = System.Text.Encoding.ASCII.GetBytes(@string); + return MD5.HashData(inputBytes); + } +} \ No newline at end of file diff --git a/C#/forSpbu/Md5Calculator/Md5Calculator.csproj b/C#/forSpbu/Md5Calculator/Md5Calculator.csproj new file mode 100644 index 0000000..151d8d4 --- /dev/null +++ b/C#/forSpbu/Md5Calculator/Md5Calculator.csproj @@ -0,0 +1,11 @@ + + + + Exe + net8.0 + Md5_calculator + enable + enable + + + diff --git a/C#/forSpbu/Md5Calculator/Program.cs b/C#/forSpbu/Md5Calculator/Program.cs new file mode 100644 index 0000000..4ac4dba --- /dev/null +++ b/C#/forSpbu/Md5Calculator/Program.cs @@ -0,0 +1,18 @@ +using Md5Calculator; + +if (args.Length != 1 || string.IsNullOrEmpty(args[0])) +{ + Console.WriteLine("Should be 1 argument with path"); + return; +} + +try +{ + var hash = await Md5Calculator.Md5Calculator.ComputeAsync("."); + Console.WriteLine(Convert.ToBase64String(hash)); +} +catch (CalculatorException e) +{ + Console.WriteLine(e.Message); + return; +} diff --git a/C#/forSpbu/forSpbu.sln b/C#/forSpbu/forSpbu.sln index 527f400..2fec020 100644 --- a/C#/forSpbu/forSpbu.sln +++ b/C#/forSpbu/forSpbu.sln @@ -10,6 +10,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "03.03", "03.03", "{882A9B9C EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "10.03", "10.03", "{EA6FC7D9-BDFB-49CD-AC00-FC5DDC5274B0}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2023", "2023", "{318796AF-A927-4A13-BAEE-FD13551DE91A}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "30.11", "30.11", "{47EB60F8-9C89-4D13-8243-B77B01A4BA53}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Md5Calculator", "Md5Calculator\Md5Calculator.csproj", "{AA2AD188-B903-46DF-AE43-4769DBF788E9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Md5Calculator.Tests", "Md5Calculator.Tests\Md5Calculator.Tests.csproj", "{F8C8BF56-097B-47CB-AF28-A2BE673CE2F5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,12 +29,23 @@ Global {E007586F-9760-4744-BB25-EDEFD6BA860C}.Release|Any CPU.ActiveCfg = Release|Any CPU {E007586F-9760-4744-BB25-EDEFD6BA860C}.Release|Any CPU.Build.0 = Release|Any CPU {A4F6ADD5-85FD-4F67-8B29-549DDDF6F82E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A4F6ADD5-85FD-4F67-8B29-549DDDF6F82E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A4F6ADD5-85FD-4F67-8B29-549DDDF6F82E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A4F6ADD5-85FD-4F67-8B29-549DDDF6F82E}.Release|Any CPU.Build.0 = Release|Any CPU + {A4F6ADD5-85FD-4F67-8B29-549DDDF6F82E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A4F6ADD5-85FD-4F67-8B29-549DDDF6F82E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A4F6ADD5-85FD-4F67-8B29-549DDDF6F82E}.Release|Any CPU.Build.0 = Release|Any CPU + {AA2AD188-B903-46DF-AE43-4769DBF788E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AA2AD188-B903-46DF-AE43-4769DBF788E9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AA2AD188-B903-46DF-AE43-4769DBF788E9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AA2AD188-B903-46DF-AE43-4769DBF788E9}.Release|Any CPU.Build.0 = Release|Any CPU + {F8C8BF56-097B-47CB-AF28-A2BE673CE2F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F8C8BF56-097B-47CB-AF28-A2BE673CE2F5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F8C8BF56-097B-47CB-AF28-A2BE673CE2F5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F8C8BF56-097B-47CB-AF28-A2BE673CE2F5}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution - {E007586F-9760-4744-BB25-EDEFD6BA860C} = {D3FCB669-E93F-4F0B-B9C5-6592CE93AC7F} + {E007586F-9760-4744-BB25-EDEFD6BA860C} = {D3FCB669-E93F-4F0B-B9C5-6592CE93AC7F} {A4F6ADD5-85FD-4F67-8B29-549DDDF6F82E} = {D3FCB669-E93F-4F0B-B9C5-6592CE93AC7F} + {47EB60F8-9C89-4D13-8243-B77B01A4BA53} = {318796AF-A927-4A13-BAEE-FD13551DE91A} + {AA2AD188-B903-46DF-AE43-4769DBF788E9} = {47EB60F8-9C89-4D13-8243-B77B01A4BA53} + {F8C8BF56-097B-47CB-AF28-A2BE673CE2F5} = {47EB60F8-9C89-4D13-8243-B77B01A4BA53} EndGlobalSection EndGlobal From d900b2a07f6193e81ade5bf64d2df01a5c3af24b Mon Sep 17 00:00:00 2001 From: IgnatSergeev Date: Thu, 30 Nov 2023 16:52:52 +0300 Subject: [PATCH 2/6] Finished --- C#/forSpbu/Md5Calculator/Md5Calculator.cs | 6 +++--- C#/forSpbu/Md5Calculator/Program.cs | 13 ++++++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/C#/forSpbu/Md5Calculator/Md5Calculator.cs b/C#/forSpbu/Md5Calculator/Md5Calculator.cs index 5595d1e..136eeb0 100644 --- a/C#/forSpbu/Md5Calculator/Md5Calculator.cs +++ b/C#/forSpbu/Md5Calculator/Md5Calculator.cs @@ -28,11 +28,10 @@ public static byte[] Compute(string path) private static async Task ComputeDirAsync(string path) { Console.WriteLine("Async dir"); - Directory.GetFiles(path).Select(file => + foreach (var file in Directory.GetFiles(path)) { Console.WriteLine(file); - return "asd"; - }); + } var fileTasks = Directory.GetFiles(path).Select(ComputeFileAsync); @@ -54,6 +53,7 @@ private static byte[] ComputeDir(string path) var dirBytes = Directory.GetDirectories(path).SelectMany(ComputeDir); var overallBytes = fileBytes.Concat(dirBytes).Concat(ComputeString(Path.GetDirectoryName(path)!)).ToArray(); + return MD5.HashData(overallBytes); } diff --git a/C#/forSpbu/Md5Calculator/Program.cs b/C#/forSpbu/Md5Calculator/Program.cs index 4ac4dba..054d05e 100644 --- a/C#/forSpbu/Md5Calculator/Program.cs +++ b/C#/forSpbu/Md5Calculator/Program.cs @@ -1,4 +1,5 @@ using Md5Calculator; +using System.Diagnostics; if (args.Length != 1 || string.IsNullOrEmpty(args[0])) { @@ -8,11 +9,17 @@ try { - var hash = await Md5Calculator.Md5Calculator.ComputeAsync("."); - Console.WriteLine(Convert.ToBase64String(hash)); + var startTime = Stopwatch.GetTimestamp(); + var hash = Md5Calculator.Md5Calculator.Compute("./Md5Calculator"); + var endTime = Stopwatch.GetTimestamp(); + Console.WriteLine($"Single thread: {Convert.ToBase64String(hash)}, {Stopwatch.GetElapsedTime(startTime, endTime)}"); + + startTime = Stopwatch.GetTimestamp(); + hash = await Md5Calculator.Md5Calculator.ComputeAsync("."); + endTime = Stopwatch.GetTimestamp(); + Console.WriteLine($"Multi thread: {Convert.ToBase64String(hash)}, {Stopwatch.GetElapsedTime(startTime, endTime)}"); } catch (CalculatorException e) { Console.WriteLine(e.Message); - return; } From 8b47f6c2bff7989139b6c2e82f384d6575723024 Mon Sep 17 00:00:00 2001 From: IgnatSergeev Date: Thu, 30 Nov 2023 20:54:45 +0300 Subject: [PATCH 3/6] Moved await --- C#/forSpbu/Md5Calculator/Md5Calculator.cs | 16 +++++++++------- C#/forSpbu/Md5Calculator/Program.cs | 10 +++++++--- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/C#/forSpbu/Md5Calculator/Md5Calculator.cs b/C#/forSpbu/Md5Calculator/Md5Calculator.cs index 136eeb0..1bcf0b3 100644 --- a/C#/forSpbu/Md5Calculator/Md5Calculator.cs +++ b/C#/forSpbu/Md5Calculator/Md5Calculator.cs @@ -32,17 +32,15 @@ private static async Task ComputeDirAsync(string path) { Console.WriteLine(file); } - var fileTasks = Directory.GetFiles(path).Select(ComputeFileAsync); var dirTasks = Directory.GetDirectories(path).Select(ComputeDirAsync); - var tasks = fileTasks.Concat(dirTasks) - .Append(new Task(() => ComputeString(Path.GetDirectoryName(path)!))) - .ToArray(); - await Task.WhenAll(tasks); + var tasks = fileTasks + .Concat(dirTasks) + .Append(new Task(() => ComputeString(Path.GetDirectoryName(path)!))); - var overallBytes = tasks.SelectMany(task => task.Result).ToArray(); + var overallBytes = (await Task.WhenAll(tasks)).SelectMany(byteArray => byteArray).ToArray(); return MD5.HashData(overallBytes); } @@ -59,7 +57,11 @@ private static byte[] ComputeDir(string path) private static async Task ComputeFileAsync(string path) { - return await MD5.HashDataAsync(File.Open(path, FileMode.Open)); + return await new Task(() => + { + var fileStream = File.Open(path, FileMode.Open); + return MD5.HashData(fileStream); + }); } private static byte[] ComputeFile(string path) diff --git a/C#/forSpbu/Md5Calculator/Program.cs b/C#/forSpbu/Md5Calculator/Program.cs index 054d05e..4da3a7c 100644 --- a/C#/forSpbu/Md5Calculator/Program.cs +++ b/C#/forSpbu/Md5Calculator/Program.cs @@ -10,12 +10,12 @@ try { var startTime = Stopwatch.GetTimestamp(); - var hash = Md5Calculator.Md5Calculator.Compute("./Md5Calculator"); + var hash = Md5Calculator.Md5Calculator.Compute(args[0]); var endTime = Stopwatch.GetTimestamp(); Console.WriteLine($"Single thread: {Convert.ToBase64String(hash)}, {Stopwatch.GetElapsedTime(startTime, endTime)}"); - + startTime = Stopwatch.GetTimestamp(); - hash = await Md5Calculator.Md5Calculator.ComputeAsync("."); + hash = await Md5Calculator.Md5Calculator.ComputeAsync(args[0]); endTime = Stopwatch.GetTimestamp(); Console.WriteLine($"Multi thread: {Convert.ToBase64String(hash)}, {Stopwatch.GetElapsedTime(startTime, endTime)}"); } @@ -23,3 +23,7 @@ { Console.WriteLine(e.Message); } +catch (IOException e) +{ + Console.WriteLine(e.Message); +} \ No newline at end of file From fe324e48829f716cd0fa0deb2dc9bb67617d6e9c Mon Sep 17 00:00:00 2001 From: IgnatSergeev Date: Thu, 30 Nov 2023 21:51:32 +0300 Subject: [PATCH 4/6] Fixed lock --- C#/forSpbu/Md5Calculator/Md5Calculator.cs | 39 +++++++---------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/C#/forSpbu/Md5Calculator/Md5Calculator.cs b/C#/forSpbu/Md5Calculator/Md5Calculator.cs index 1bcf0b3..a4a95a9 100644 --- a/C#/forSpbu/Md5Calculator/Md5Calculator.cs +++ b/C#/forSpbu/Md5Calculator/Md5Calculator.cs @@ -27,20 +27,16 @@ public static byte[] Compute(string path) private static async Task ComputeDirAsync(string path) { - Console.WriteLine("Async dir"); - foreach (var file in Directory.GetFiles(path)) - { - Console.WriteLine(file); - } var fileTasks = Directory.GetFiles(path).Select(ComputeFileAsync); var dirTasks = Directory.GetDirectories(path).Select(ComputeDirAsync); - var tasks = fileTasks - .Concat(dirTasks) - .Append(new Task(() => ComputeString(Path.GetDirectoryName(path)!))); + var tasks = fileTasks.Concat(dirTasks).ToArray(); - var overallBytes = (await Task.WhenAll(tasks)).SelectMany(byteArray => byteArray).ToArray(); + var overallBytes = (await Task.WhenAll(tasks)) + .SelectMany(byteArray => byteArray) + .Concat(ComputeString(Path.GetDirectoryName(path)!)) + .ToArray(); return MD5.HashData(overallBytes); } @@ -54,24 +50,13 @@ private static byte[] ComputeDir(string path) return MD5.HashData(overallBytes); } + + private static async Task ComputeFileAsync(string path) => + await MD5.HashDataAsync(new FileInfo(path).OpenRead()); - private static async Task ComputeFileAsync(string path) - { - return await new Task(() => - { - var fileStream = File.Open(path, FileMode.Open); - return MD5.HashData(fileStream); - }); - } - - private static byte[] ComputeFile(string path) - { - return MD5.HashData(File.Open(path, FileMode.Open)); - } + private static byte[] ComputeFile(string path) => + MD5.HashData(new FileInfo(path).OpenRead()); - private static byte[] ComputeString(string @string) - { - var inputBytes = System.Text.Encoding.ASCII.GetBytes(@string); - return MD5.HashData(inputBytes); - } + private static byte[] ComputeString(string @string) => + MD5.HashData(System.Text.Encoding.ASCII.GetBytes(@string)); } \ No newline at end of file From 63e573cc362f63254e94db9afd69da299e40b3ee Mon Sep 17 00:00:00 2001 From: IgnatSergeev Date: Thu, 30 Nov 2023 21:54:08 +0300 Subject: [PATCH 5/6] Added comments --- C#/forSpbu/Md5Calculator/CalculatorException.cs | 10 ++++++++++ C#/forSpbu/Md5Calculator/Md5Calculator.cs | 15 +++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/C#/forSpbu/Md5Calculator/CalculatorException.cs b/C#/forSpbu/Md5Calculator/CalculatorException.cs index 761ffc4..da260d8 100644 --- a/C#/forSpbu/Md5Calculator/CalculatorException.cs +++ b/C#/forSpbu/Md5Calculator/CalculatorException.cs @@ -1,11 +1,21 @@ namespace Md5Calculator; +/// +/// Represents exception thrown in Md5 calculator +/// public class CalculatorException : ArgumentException { + /// + /// Creates exception with message + /// + /// Exception message public CalculatorException(string message) : base(message) { } + /// + /// Creates empty exception + /// public CalculatorException() { } diff --git a/C#/forSpbu/Md5Calculator/Md5Calculator.cs b/C#/forSpbu/Md5Calculator/Md5Calculator.cs index a4a95a9..898c410 100644 --- a/C#/forSpbu/Md5Calculator/Md5Calculator.cs +++ b/C#/forSpbu/Md5Calculator/Md5Calculator.cs @@ -2,8 +2,17 @@ namespace Md5Calculator; using System.Security.Cryptography; +/// +/// Represents md5 hash calculator +/// public static class Md5Calculator { + /// + /// Asynchronously computes md5 hash of given path + /// + /// Path to compute + /// Hash as byte array + /// If given does not exist public static async Task ComputeAsync(string path) { if (!Directory.Exists(path) && !File.Exists(path)) @@ -14,6 +23,12 @@ public static async Task ComputeAsync(string path) return !Directory.Exists(path) ? await ComputeFileAsync(path) : await ComputeDirAsync(path); } + /// + /// Synchronously computes md5 hash of given path + /// + /// Path to compute + /// Hash as byte array + /// If given does not exist public static byte[] Compute(string path) { if (!Directory.Exists(path) && !File.Exists(path)) From a682963fa6e600cefe1dd6bb12414309b70b9e55 Mon Sep 17 00:00:00 2001 From: IgnatSergeev Date: Thu, 30 Nov 2023 23:20:26 +0300 Subject: [PATCH 6/6] Added tests --- .../Md5Calculator.Tests/GlobalUsings.cs | 1 + .../Md5Calculator.Tests.csproj | 24 +++ .../Md5Calculator.Tests/Md5CalculatorTests.cs | 160 ++++++++++++++++++ C#/forSpbu/Md5Calculator/Md5Calculator.cs | 20 ++- C#/forSpbu/forSpbu.sln | 12 +- 5 files changed, 204 insertions(+), 13 deletions(-) create mode 100644 C#/forSpbu/Md5Calculator.Tests/GlobalUsings.cs create mode 100644 C#/forSpbu/Md5Calculator.Tests/Md5Calculator.Tests.csproj create mode 100644 C#/forSpbu/Md5Calculator.Tests/Md5CalculatorTests.cs diff --git a/C#/forSpbu/Md5Calculator.Tests/GlobalUsings.cs b/C#/forSpbu/Md5Calculator.Tests/GlobalUsings.cs new file mode 100644 index 0000000..cefced4 --- /dev/null +++ b/C#/forSpbu/Md5Calculator.Tests/GlobalUsings.cs @@ -0,0 +1 @@ +global using NUnit.Framework; \ No newline at end of file diff --git a/C#/forSpbu/Md5Calculator.Tests/Md5Calculator.Tests.csproj b/C#/forSpbu/Md5Calculator.Tests/Md5Calculator.Tests.csproj new file mode 100644 index 0000000..a7fc770 --- /dev/null +++ b/C#/forSpbu/Md5Calculator.Tests/Md5Calculator.Tests.csproj @@ -0,0 +1,24 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + diff --git a/C#/forSpbu/Md5Calculator.Tests/Md5CalculatorTests.cs b/C#/forSpbu/Md5Calculator.Tests/Md5CalculatorTests.cs new file mode 100644 index 0000000..8eb4b10 --- /dev/null +++ b/C#/forSpbu/Md5Calculator.Tests/Md5CalculatorTests.cs @@ -0,0 +1,160 @@ +namespace Md5Calculator.Tests; + +public class Md5CalculatorTests +{ + private static IEnumerable> ComputeInstances() + { + yield return Md5Calculator.Compute; + yield return path => Md5Calculator.ComputeAsync(path).Result; + } + + [Test] + public void AsyncEqualsSyncTest() + { + var dirNames = new [] + { + "./AsyncEqualsSyncTest", + "./AsyncEqualsSyncTest/Dir1", + }; + (string path, string data)[] files = new [] + { + ("./AsyncEqualsSyncTest/Dir1/file1.txt", "Asd"), + ("./AsyncEqualsSyncTest/file1.txt", "Asd"), + }; + dirNames.AsParallel().ForAll(path => Directory.CreateDirectory(path)); + files.AsParallel() + .ForAll(file => File.WriteAllBytes(file.path, System.Text.Encoding.ASCII.GetBytes(file.data))); + + Assert.That(Md5Calculator.Compute(dirNames[0]), Is.EqualTo(Md5Calculator.ComputeAsync(dirNames[0]).Result)); + + files.AsParallel() + .ForAll(file => File.Delete(file.path)); + Directory.Delete(dirNames[1]); + } + + [Test, TestCaseSource(nameof(ComputeInstances))] + public void RecalculateEqualsTest(Func compute) + { + var dirNames = new [] + { + "./RecalculateEqualsTest", + "./RecalculateEqualsTest/Dir1", + }; + (string path, string data)[] files = new [] + { + ("./RecalculateEqualsTest/Dir1/file1.txt", "Asd"), + ("./RecalculateEqualsTest/file1.txt", "Asd"), + }; + dirNames.AsParallel().ForAll(path => Directory.CreateDirectory(path)); + files.AsParallel() + .ForAll(file => File.WriteAllBytes(file.path, System.Text.Encoding.ASCII.GetBytes(file.data))); + + Assert.That(compute(dirNames[0]), Is.EqualTo(compute(dirNames[0]))); + + files.AsParallel() + .ForAll(file => File.Delete(file.path)); + Directory.Delete(dirNames[1]); + } + + [Test, TestCaseSource(nameof(ComputeInstances))] + public void FileNameMattersTest(Func compute) + { + var dirNames = new [] + { + "./FileNameMattersTest", + }; + (string path, string data)[] files = new [] + { + ("./FileNameMattersTest/file2.txt", "Asd"), + ("./FileNameMattersTest/file1.txt", "Asd"), + }; + dirNames.AsParallel().ForAll(path => Directory.CreateDirectory(path)); + files.AsParallel() + .ForAll(file => File.WriteAllBytes(file.path, System.Text.Encoding.ASCII.GetBytes(file.data))); + + Assert.That(compute(files[0].path), Is.Not.EqualTo(compute(files[1].path))); + + files.AsParallel() + .ForAll(file => File.Delete(file.path)); + } + + [Test, TestCaseSource(nameof(ComputeInstances))] + public void DirNameMattersTest(Func compute) + { + var dirNames = new [] + { + "./DirNameMattersTest/Dir1", + "./DirNameMattersTest/Dirs5", + }; + (string path, string data)[] files = new [] + { + ("./DirNameMattersTest/Dir1/file1.txt", "Asd"), + ("./DirNameMattersTest/Dirs5/file1.txt", "Asd"), + }; + dirNames.AsParallel().ForAll(path => Directory.CreateDirectory(path)); + files.AsParallel() + .ForAll(file => File.WriteAllBytes(file.path, System.Text.Encoding.ASCII.GetBytes(file.data))); + + Assert.That(compute(dirNames[0]), Is.Not.EqualTo(compute(dirNames[1]))); + + files.AsParallel() + .ForAll(file => File.Delete(file.path)); + dirNames.AsParallel().ForAll(path => Directory.Delete(path)); + } + + [Test, TestCaseSource(nameof(ComputeInstances))] + public void DirFilesMatterTest(Func compute) + { + var dirNames = new [] + { + "./DirFilesMatterTest/Dir1", + "./DirFilesMatterTest/Dir2", + }; + (string path, string data)[] files = new [] + { + ("./DirFilesMatterTest/Dir1/file1.txt", "Asd"), + ("./DirFilesMatterTest/Dir2/file1.txt", "Asde"), + }; + dirNames.AsParallel().ForAll(path => Directory.CreateDirectory(path)); + files.AsParallel() + .ForAll(file => File.WriteAllBytes(file.path, System.Text.Encoding.ASCII.GetBytes(file.data))); + + Assert.That(compute(dirNames[0]), Is.Not.EqualTo(compute(dirNames[1]))); + + files.AsParallel() + .ForAll(file => File.Delete(file.path)); + dirNames.AsParallel().ForAll(path => Directory.Delete(path)); + } + + [Test, TestCaseSource(nameof(ComputeInstances))] + public void SubDirsMatterTest(Func compute) + { + var dirNames = new [] + { + "./SubDirsMatterTest/Dir1", + "./SubDirsMatterTest/Dir2", + "./SubDirsMatterTest/Dir1/Dir11", + "./SubDirsMatterTest/Dir2/Dir21", + }; + (string path, string data)[] files = new [] + { + ("./SubDirsMatterTest/Dir1/Dir11/file1.txt", "Asd"), + ("./SubDirsMatterTest/Dir2/Dir21/file1.txt", "Asde"), + }; + dirNames.AsParallel().ForAll(path => Directory.CreateDirectory(path)); + files.AsParallel() + .ForAll(file => File.WriteAllBytes(file.path, System.Text.Encoding.ASCII.GetBytes(file.data))); + + Assert.That(compute(dirNames[0]), Is.Not.EqualTo(compute(dirNames[1]))); + + files.AsParallel() + .ForAll(file => File.Delete(file.path)); + Directory.Delete(dirNames[3]); + Directory.Delete(dirNames[2]); + Directory.Delete(dirNames[1]); + Directory.Delete(dirNames[0]); + + + + } +} \ No newline at end of file diff --git a/C#/forSpbu/Md5Calculator/Md5Calculator.cs b/C#/forSpbu/Md5Calculator/Md5Calculator.cs index 898c410..af3796a 100644 --- a/C#/forSpbu/Md5Calculator/Md5Calculator.cs +++ b/C#/forSpbu/Md5Calculator/Md5Calculator.cs @@ -50,7 +50,7 @@ private static async Task ComputeDirAsync(string path) var overallBytes = (await Task.WhenAll(tasks)) .SelectMany(byteArray => byteArray) - .Concat(ComputeString(Path.GetDirectoryName(path)!)) + .Concat(ComputeString(new DirectoryInfo(path).Name)) .ToArray(); return MD5.HashData(overallBytes); } @@ -61,16 +61,22 @@ private static byte[] ComputeDir(string path) var dirBytes = Directory.GetDirectories(path).SelectMany(ComputeDir); - var overallBytes = fileBytes.Concat(dirBytes).Concat(ComputeString(Path.GetDirectoryName(path)!)).ToArray(); + var overallBytes = fileBytes.Concat(dirBytes).Concat(ComputeString(new DirectoryInfo(path).Name)).ToArray(); return MD5.HashData(overallBytes); } - private static async Task ComputeFileAsync(string path) => - await MD5.HashDataAsync(new FileInfo(path).OpenRead()); - - private static byte[] ComputeFile(string path) => - MD5.HashData(new FileInfo(path).OpenRead()); + private static async Task ComputeFileAsync(string path) + { + var byteArray = (await MD5.HashDataAsync(new FileInfo(path).OpenRead())).Concat(ComputeString(new FileInfo(path).Name)).ToArray(); + return MD5.HashData(byteArray); + } + + private static byte[] ComputeFile(string path) + { + var byteArray = MD5.HashData(new FileInfo(path).OpenRead()).Concat(ComputeString(new FileInfo(path).Name)).ToArray(); + return MD5.HashData(byteArray); + } private static byte[] ComputeString(string @string) => MD5.HashData(System.Text.Encoding.ASCII.GetBytes(@string)); diff --git a/C#/forSpbu/forSpbu.sln b/C#/forSpbu/forSpbu.sln index 2fec020..d68c9cf 100644 --- a/C#/forSpbu/forSpbu.sln +++ b/C#/forSpbu/forSpbu.sln @@ -16,7 +16,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "30.11", "30.11", "{47EB60F8 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Md5Calculator", "Md5Calculator\Md5Calculator.csproj", "{AA2AD188-B903-46DF-AE43-4769DBF788E9}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Md5Calculator.Tests", "Md5Calculator.Tests\Md5Calculator.Tests.csproj", "{F8C8BF56-097B-47CB-AF28-A2BE673CE2F5}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Md5Calculator.Tests", "Md5Calculator.Tests\Md5Calculator.Tests.csproj", "{6A71CD77-320C-458F-97B3-BA8F4CB530C6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -36,16 +36,16 @@ Global {AA2AD188-B903-46DF-AE43-4769DBF788E9}.Debug|Any CPU.Build.0 = Debug|Any CPU {AA2AD188-B903-46DF-AE43-4769DBF788E9}.Release|Any CPU.ActiveCfg = Release|Any CPU {AA2AD188-B903-46DF-AE43-4769DBF788E9}.Release|Any CPU.Build.0 = Release|Any CPU - {F8C8BF56-097B-47CB-AF28-A2BE673CE2F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F8C8BF56-097B-47CB-AF28-A2BE673CE2F5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F8C8BF56-097B-47CB-AF28-A2BE673CE2F5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F8C8BF56-097B-47CB-AF28-A2BE673CE2F5}.Release|Any CPU.Build.0 = Release|Any CPU + {6A71CD77-320C-458F-97B3-BA8F4CB530C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6A71CD77-320C-458F-97B3-BA8F4CB530C6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6A71CD77-320C-458F-97B3-BA8F4CB530C6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6A71CD77-320C-458F-97B3-BA8F4CB530C6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {E007586F-9760-4744-BB25-EDEFD6BA860C} = {D3FCB669-E93F-4F0B-B9C5-6592CE93AC7F} {A4F6ADD5-85FD-4F67-8B29-549DDDF6F82E} = {D3FCB669-E93F-4F0B-B9C5-6592CE93AC7F} {47EB60F8-9C89-4D13-8243-B77B01A4BA53} = {318796AF-A927-4A13-BAEE-FD13551DE91A} {AA2AD188-B903-46DF-AE43-4769DBF788E9} = {47EB60F8-9C89-4D13-8243-B77B01A4BA53} - {F8C8BF56-097B-47CB-AF28-A2BE673CE2F5} = {47EB60F8-9C89-4D13-8243-B77B01A4BA53} + {6A71CD77-320C-458F-97B3-BA8F4CB530C6} = {47EB60F8-9C89-4D13-8243-B77B01A4BA53} EndGlobalSection EndGlobal