From 06fd2d8f2fb81a0e34c01b5ba8563ad63ec25197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9B=D0=B8=D1=8F=D1=81=D0=BE=D0=B2=20=D0=98=D0=BB=D1=8C?= =?UTF-8?q?=D1=8F=20=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B5=D0=B2=D0=B8=D1=87?= Date: Tue, 5 Nov 2024 09:32:04 +0500 Subject: [PATCH] update to .net 8 --- .gitignore | 3 + Exceptions.sln | 4 +- Exceptions/Converter.cs | 120 ++++++++++++++++ Exceptions/ConverterProgram.cs | 122 ----------------- Exceptions/ConverterProgram_Should.cs | 153 --------------------- Exceptions/Converter_Should.cs | 143 +++++++++++++++++++ Exceptions/Exceptions.csproj | 16 ++- Exceptions/Program.cs | 3 + Exceptions/ReportReceiver.cs | 56 -------- Exceptions/ReportingTest.cs | 189 +++++++++++++------------- Exceptions/Samples/ReportReceiver.cs | 45 ++++++ Exceptions/Settings.cs | 21 +-- Exceptions/Solved/Converter_Solved.cs | 127 +++++++++++++++++ Exceptions/Solved/ErrorHandler.cs | 44 +++--- Exceptions/Solved/Program_Solved.cs | 131 ------------------ Exceptions/settings.json | 4 + Exceptions/settings.xml | 5 - 17 files changed, 573 insertions(+), 613 deletions(-) create mode 100644 Exceptions/Converter.cs delete mode 100644 Exceptions/ConverterProgram.cs delete mode 100644 Exceptions/ConverterProgram_Should.cs create mode 100644 Exceptions/Converter_Should.cs create mode 100644 Exceptions/Program.cs delete mode 100644 Exceptions/ReportReceiver.cs create mode 100644 Exceptions/Samples/ReportReceiver.cs create mode 100644 Exceptions/Solved/Converter_Solved.cs delete mode 100644 Exceptions/Solved/Program_Solved.cs create mode 100644 Exceptions/settings.json delete mode 100644 Exceptions/settings.xml diff --git a/.gitignore b/.gitignore index e65efed..a2ad02a 100644 --- a/.gitignore +++ b/.gitignore @@ -235,3 +235,6 @@ _Pvt_Extensions # FAKE - F# Make .fake/ + +# VS Code +.vscode/ \ No newline at end of file diff --git a/Exceptions.sln b/Exceptions.sln index 26fe114..d672ef1 100644 --- a/Exceptions.sln +++ b/Exceptions.sln @@ -1,9 +1,9 @@ - + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.25123.0 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Exceptions", "Exceptions\Exceptions.csproj", "{E837A77F-C3E7-4756-95DC-C41D6A46CF4B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Exceptions", "Exceptions\Exceptions.csproj", "{E837A77F-C3E7-4756-95DC-C41D6A46CF4B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/Exceptions/Converter.cs b/Exceptions/Converter.cs new file mode 100644 index 0000000..3b77ad6 --- /dev/null +++ b/Exceptions/Converter.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using NLog; + +namespace Exceptions; + +public class Converter +{ + private static readonly Logger log = LogManager.GetCurrentClassLogger(); + + public static void ConvertFiles(params string[] filenames) + { + try + { + filenames = filenames.Length > 0 ? filenames : new[] { "text.txt" }; + var settings = LoadSettings(); + ConvertFiles(filenames, settings); + } + catch (Exception e) + { + log.Error(e); + } + } + + private static void ConvertFiles(string[] filenames, Settings settings) + { + var tasks = filenames + .Select(fn => Task.Run(() => ConvertFile(fn, settings))) + .ToArray(); + Task.WaitAll(tasks); + } + + private static Settings LoadSettings() + { + using var stream = new FileStream("settings.json", FileMode.Open); + return JsonSerializer.Deserialize(stream); + } + + private static void ConvertFile(string filename, Settings settings) + { + Thread.CurrentThread.CurrentCulture = new CultureInfo(settings.SourceCultureName); + if (settings.Verbose) + { + log.Info("Processing file " + filename); + log.Info("Source Culture " + Thread.CurrentThread.CurrentCulture.Name); + } + IEnumerable lines; + try + { + lines = PrepareLines(filename); + } + catch + { + log.Error($"File {filename} not found"); + return; + } + var convertedLines = lines + .Select(ConvertLine) + .Select(s => s.Length + " " + s); + File.WriteAllLines(filename + ".out", convertedLines); + } + + private static IEnumerable PrepareLines(string filename) + { + var lineIndex = 0; + foreach (var line in File.ReadLines(filename)) + { + if (line == string.Empty) continue; + yield return line.Trim(); + lineIndex++; + } + yield return lineIndex.ToString(); + } + + public static string ConvertLine(string arg) + { + try + { + return ConvertAsDateTime(arg); + } + catch + { + try + { + return ConvertAsDouble(arg); + } + catch + { + return ConvertAsCharIndexInstruction(arg); + } + } + } + + private static string ConvertAsCharIndexInstruction(string s) + { + var parts = s.Split(); + if (parts.Length < 2) return null; + var charIndex = int.Parse(parts[0]); + if ((charIndex < 0) || (charIndex >= parts[1].Length)) + return null; + var text = parts[1]; + return text[charIndex].ToString(); + } + + private static string ConvertAsDateTime(string arg) + { + return DateTime.Parse(arg).ToString(CultureInfo.InvariantCulture); + } + + private static string ConvertAsDouble(string arg) + { + return double.Parse(arg).ToString(CultureInfo.InvariantCulture); + } +} diff --git a/Exceptions/ConverterProgram.cs b/Exceptions/ConverterProgram.cs deleted file mode 100644 index f9e522b..0000000 --- a/Exceptions/ConverterProgram.cs +++ /dev/null @@ -1,122 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using System.Xml.Serialization; -using NLog; - -namespace Exceptions -{ - public class ConverterProgram - { - private static readonly Logger log = LogManager.GetCurrentClassLogger(); - - public static void Main(params string[] args) - { - try - { - var filenames = args.Any() ? args : new[] { "text.txt" }; - var settings = LoadSettings(); - ConvertFiles(filenames, settings); - } - catch (Exception e) - { - log.Error(e); - } - } - - private static void ConvertFiles(string[] filenames, Settings settings) - { - var tasks = filenames - .Select(fn => Task.Run(() => ConvertFile(fn, settings))) - .ToArray(); - Task.WaitAll(tasks); - } - - private static Settings LoadSettings() - { - var serializer = new XmlSerializer(typeof(Settings)); - var content = File.ReadAllText("settings.xml"); - return (Settings) serializer.Deserialize(new StringReader(content)); - } - - private static void ConvertFile(string filename, Settings settings) - { - Thread.CurrentThread.CurrentCulture = new CultureInfo(settings.SourceCultureName); - if (settings.Verbose) - { - log.Info("Processing file " + filename); - log.Info("Source Culture " + Thread.CurrentThread.CurrentCulture.Name); - } - IEnumerable lines; - try - { - lines = PrepareLines(filename); - } - catch - { - log.Error($"File {filename} not found"); - return; - } - var convertedLines = lines - .Select(ConvertLine) - .Select(s => s.Length + " " + s); - File.WriteAllLines(filename + ".out", convertedLines); - } - - private static IEnumerable PrepareLines(string filename) - { - var lineIndex = 0; - foreach (var line in File.ReadLines(filename)) - { - if (line == "") continue; - yield return line.Trim(); - lineIndex++; - } - yield return lineIndex.ToString(); - } - - public static string ConvertLine(string arg) - { - try - { - return ConvertAsDateTime(arg); - } - catch - { - try - { - return ConvertAsDouble(arg); - } - catch - { - return ConvertAsCharIndexInstruction(arg); - } - } - } - - private static string ConvertAsCharIndexInstruction(string s) - { - var parts = s.Split(); - if (parts.Length < 2) return null; - var charIndex = int.Parse(parts[0]); - if ((charIndex < 0) || (charIndex >= parts[1].Length)) - return null; - var text = parts[1]; - return text[charIndex].ToString(); - } - - private static string ConvertAsDateTime(string arg) - { - return DateTime.Parse(arg).ToString(CultureInfo.InvariantCulture); - } - - private static string ConvertAsDouble(string arg) - { - return double.Parse(arg).ToString(CultureInfo.InvariantCulture); - } - } -} \ No newline at end of file diff --git a/Exceptions/ConverterProgram_Should.cs b/Exceptions/ConverterProgram_Should.cs deleted file mode 100644 index 08450f9..0000000 --- a/Exceptions/ConverterProgram_Should.cs +++ /dev/null @@ -1,153 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Xml.Serialization; -using NLog.Config; -using NLog.Targets; -using NUnit.Framework; - -namespace Exceptions -{ - [TestFixture] - public class ConverterProgram_Should : ReportingTest - { - // ReSharper disable once UnusedMember.Global - public static string Names = "ВАШИ ФАМИЛИИ ЧЕРЕЗ ПРОБЕЛ"; // Ivanov Petrov - - private MemoryTarget log; - - [SetUp] - public void SetUp() - { - log = new MemoryTarget(); - SimpleConfigurator.ConfigureForTargetLogging(log); - log.Layout = "${longdate} ${uppercase:${level}} ${message} ${exception:format=tostring}"; - // Uncomment the next line if tests fails due to UnauthorizedAccessException - // Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory); - File.Delete("text.txt.out"); - } - - [TearDown] - public void TearDown() - { - foreach (var message in log.Logs) - Console.WriteLine(message); - } - - - [TestCase("ru", "1,12", TestName = "double")] - [TestCase("ru", "15.11.1982", TestName = "date")] - [TestCase("ru", "1 asdasd", TestName = "char")] - [TestCase("ru", "1\n1,12\n15.11.1982\n1 qwe", TestName = "mixed")] - [TestCase("en", "1.12", TestName = "en double")] - [TestCase("en", "12/31/2017", TestName = "en date")] - public void Convert(string sourceCulture, string input) - { - Arrange( - new Settings { SourceCultureName = sourceCulture, Verbose = false }, - input - ); - - ConverterProgram.Main("text.txt"); - - Assert.IsTrue(File.Exists("text.txt.out")); - Assert.IsEmpty(log.Logs); - } - - [TestCase("2017-01-01", TestName = "correct date")] - [TestCase("123", TestName = "correct number")] - public void ConvertFast(string input) - { - #region warm_up - ConverterProgram.ConvertLine(input); - DateTime.TryParse(input, out var d1); - #endregion - - var time = Measure(input, s => DateTime.TryParse(s, out var d) ? d.ToString() : s); - var time2 = Measure(input, ConverterProgram.ConvertLine); - Console.WriteLine(time); - Console.WriteLine(time2); - Assert.Less(time2.TotalMilliseconds, 10*time.TotalMilliseconds, "ConvertLine is too slow! (more than 10 times slower than just DateTime.TryParse)"); - } - - private static TimeSpan Measure(string input, Func action) - { - var timer = Stopwatch.StartNew(); - for (var i = 0; i < 100000; i++) - { - action(input); - } - timer.Stop(); - return timer.Elapsed; - } - - [Test] - public void Fail_IfSettingslIncorrect() - { - File.WriteAllText("settings.xml", "NOT XML AT ALL!"); - - ConverterProgram.Main(); - - var errorMessage = log.Logs[0]; - Assert.That(errorMessage, Does.Match("Не удалось прочитать файл настроек")); - Assert.That(errorMessage, Does.Match("XmlException")); - Assert.That(log.Logs.Count, Is.EqualTo(1)); - } - - [Test] - public void Fail_WhenNoFile() - { - Arrange(Settings.Default, "123"); - var filename = Guid.NewGuid().ToString(); - ConverterProgram.Main(filename); - - var errorMessage = log.Logs[0]; - Assert.That(errorMessage, Does.Match($"Не удалось сконвертировать {filename}")); - Assert.That(errorMessage, Does.Match("FileNotFoundException")); - Assert.AreEqual(1, log.Logs.Count); - } - - [TestCase("abracadabra", TestName = "abracadabra")] - [TestCase("100500 a", TestName = "wrong char index")] - public void FailOn(string input) - { - Arrange(Settings.Default, input); - - ConverterProgram.Main(); - - var errorMessage = log.Logs[0]; - Assert.That(errorMessage, Does.Not.Match("AggregateException")); - Assert.That(errorMessage, Does.Match("Некорректная строка")); - Assert.AreEqual(1, log.Logs.Count); - } - - [Test] - public void UseDefaultSettings_IfNoSettings() - { - Arrange(Settings.Default, "123"); - File.Delete("settings.xml"); - - ConverterProgram.Main(); - - Assert.That(log.Logs[0], Does.Match("Файл настроек .* отсутствует.")); - Assert.That(log.Logs.Count, Is.EqualTo(1)); - Assert.IsTrue(File.Exists("text.txt.out")); - } - - private void Arrange(Settings settings, string input) - { - SaveSettings(settings); - File.WriteAllText("text.txt", input); - } - - private static void SaveSettings(Settings settings) - { - var serializer = new XmlSerializer(typeof(Settings)); - using (var stream = new FileStream("settings.xml", FileMode.OpenOrCreate)) - { - serializer.Serialize(stream, settings); - } - } - - } -} \ No newline at end of file diff --git a/Exceptions/Converter_Should.cs b/Exceptions/Converter_Should.cs new file mode 100644 index 0000000..bedf799 --- /dev/null +++ b/Exceptions/Converter_Should.cs @@ -0,0 +1,143 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Text.Json; +using NLog.Config; +using NLog.Targets; +using NUnit.Framework; + +namespace Exceptions; + +[TestFixture] +public class Converter_Should : ReportingTest +{ + // ReSharper disable once UnusedMember.Global + #pragma warning disable CA2211 // Non-constant fields should not be visible + public static string Names = "ВАШИ ФАМИЛИИ ЧЕРЕЗ ПРОБЕЛ"; // Ivanov Petrov + + private MemoryTarget log; + + [SetUp] + public void SetUp() + { + log = new MemoryTarget(); + SimpleConfigurator.ConfigureForTargetLogging(log); + log.Layout = "${longdate} ${uppercase:${level}} ${message} ${exception:format=tostring}"; + // Uncomment the next line if tests fails due to UnauthorizedAccessException + // Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory); + File.Delete("text.txt.out"); + } + + [TearDown] + public void TearDown() + { + foreach (var message in log.Logs) + Console.WriteLine(message); + } + + [TestCase("ru", "1,12", TestName = "double")] + [TestCase("ru", "15.11.1982", TestName = "date")] + [TestCase("ru", "1 asdasd", TestName = "char")] + [TestCase("ru", "1\n1,12\n15.11.1982\n1 qwe", TestName = "mixed")] + [TestCase("en", "1.12", TestName = "en double")] + [TestCase("en", "12/31/2017", TestName = "en date")] + public void Convert(string sourceCulture, string input) + { + Arrange(new Settings(sourceCulture, Verbose: false), input); + + Converter.ConvertFiles("text.txt"); + + Assert.That(File.Exists("text.txt.out")); + Assert.That(log.Logs, Is.Empty); + } + + [TestCase("2017-01-01", TestName = "correct date")] + [TestCase("123", TestName = "correct number")] + public void ConvertFast(string input) + { + #region warm_up + Converter.ConvertLine(input); + DateTime.TryParse(input, out _); + #endregion + + var time = Measure(input, s => DateTime.TryParse(s, out var d) ? d.ToString() : s); + var time2 = Measure(input, Converter.ConvertLine); + Console.WriteLine(time); + Console.WriteLine(time2); + Assert.That(time2.TotalMilliseconds, Is.LessThan(10 * time.TotalMilliseconds), "ConvertLine is too slow! (more than 10 times slower than just DateTime.TryParse)"); + } + + [Test] + public void Fail_WhenIncorrectSettingsFile() + { + File.WriteAllText("settings.json", "NOT JSON AT ALL!"); + + Converter.ConvertFiles(); + + var errorMessage = log.Logs[0]; + Assert.That(errorMessage, Does.Match("Не удалось прочитать файл настроек")); + Assert.That(errorMessage, Does.Match("JsonException")); + Assert.That(log.Logs.Count, Is.EqualTo(1)); + } + + [Test] + public void Fail_WhenNoSettingsFile() + { + Arrange(Settings.Default, "123"); + var filename = Guid.NewGuid().ToString(); + Converter.ConvertFiles(filename); + + var errorMessage = log.Logs[0]; + Assert.That(errorMessage, Does.Match($"Не удалось сконвертировать {filename}")); + Assert.That(errorMessage, Does.Match("FileNotFoundException")); + Assert.That(log.Logs.Count, Is.EqualTo(1)); + } + + [TestCase("abracadabra", TestName = "abracadabra")] + [TestCase("100500 a", TestName = "wrong char index")] + public void FailOn(string input) + { + Arrange(Settings.Default, input); + + Converter.ConvertFiles(); + + var errorMessage = log.Logs[0]; + Assert.That(errorMessage, Does.Not.Match("AggregateException")); + Assert.That(errorMessage, Does.Match("Некорректная строка")); + Assert.That(log.Logs.Count, Is.EqualTo(1)); + } + + [Test] + public void UseDefaultSettings_WhenNoSettingsFile() + { + Arrange(Settings.Default, "123"); + File.Delete("settings.json"); + + Converter.ConvertFiles(); + + Assert.That(log.Logs[0], Does.Match("Файл настроек .* отсутствует.")); + Assert.That(log.Logs.Count, Is.EqualTo(1)); + Assert.That(File.Exists("text.txt.out")); + } + + private static void Arrange(Settings settings, string input) + { + SaveSettings(settings); + File.WriteAllText("text.txt", input); + } + + private static void SaveSettings(Settings settings) + { + using var stream = new FileStream("settings.json", FileMode.Truncate); + JsonSerializer.Serialize(stream, settings); + } + + private static TimeSpan Measure(string input, Func action) + { + var ts = Stopwatch.GetTimestamp(); + for (var i = 0; i < 100_000; i++) + action(input); + + return Stopwatch.GetElapsedTime(ts); + } +} \ No newline at end of file diff --git a/Exceptions/Exceptions.csproj b/Exceptions/Exceptions.csproj index 67c8ab1..5a0430b 100644 --- a/Exceptions/Exceptions.csproj +++ b/Exceptions/Exceptions.csproj @@ -1,22 +1,24 @@  - 8 - net48 + net8.0 + 11 false + false - - + + - + + - + Always @@ -25,4 +27,4 @@ - + \ No newline at end of file diff --git a/Exceptions/Program.cs b/Exceptions/Program.cs new file mode 100644 index 0000000..2ff1077 --- /dev/null +++ b/Exceptions/Program.cs @@ -0,0 +1,3 @@ +using Exceptions; + +Converter.ConvertFiles(args); \ No newline at end of file diff --git a/Exceptions/ReportReceiver.cs b/Exceptions/ReportReceiver.cs deleted file mode 100644 index 3b0cb31..0000000 --- a/Exceptions/ReportReceiver.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Collections.Generic; -// ReSharper disable CollectionNeverQueried.Local -// ReSharper disable FieldCanBeMadeReadOnly.Local - -namespace Exceptions -{ - // Что тут не так? - public class ReportReceiver - { - private Dictionary reportsCache - = new Dictionary(); - private Dictionary sendersCache - = new Dictionary(); - private Dictionary receiversCache - = new Dictionary(); - private readonly OrganizationRepo organizationsRepo; - - public ReportReceiver(OrganizationRepo organizationsRepo) - { - this.organizationsRepo = organizationsRepo; - } - - public void ReceiveReport(Report report) - { - if (!reportsCache.ContainsKey(report.Id)) - { - sendersCache.Add(report.Id, organizationsRepo.Get(report.SenderId)); - receiversCache.Add(report.Id, organizationsRepo.Get(report.ReceiverId)); - reportsCache.Add(report.Id, report); - } - } - - //... - } - - - public class OrganizationRepo - { - public Organization Get(Guid senderId) - { - throw new NotImplementedException(); - } - } - - public class Organization - { - } - - public class Report - { - public Guid Id { get; private set; } - public Guid SenderId { get; private set; } - public Guid ReceiverId { get; private set; } - } -} \ No newline at end of file diff --git a/Exceptions/ReportingTest.cs b/Exceptions/ReportingTest.cs index c772f39..50b5ec2 100644 --- a/Exceptions/ReportingTest.cs +++ b/Exceptions/ReportingTest.cs @@ -2,125 +2,120 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using FireSharp; -using FireSharp.Config; -using Newtonsoft.Json; +using System.Text.Json; +using System.Threading.Tasks; +using Firebase.Database; +using Firebase.Database.Query; using NUnit.Framework; using NUnit.Framework.Interfaces; -namespace Exceptions +namespace Exceptions; + +public static class Firebase { - public static class Firebase + public static FirebaseClient CreateClient() => new(BuildBaseUrl()); + + private static string BuildBaseUrl() { - private static FirebaseConfig BuildConfig() - { - const string Url = "https://testing-challenge.firebaseio.com"; - const string Realm = "exceptions"; - var dateKey = DateTime.Now.Date.ToString("yyyyMMdd"); + const string Url = "https://testing-challenge.firebaseio.com"; + const string Realm = "exceptions"; + var dateKey = DateTime.Now.Date.ToString("yyyyMMdd"); - var config = new FirebaseConfig - { - BasePath = $"{Url}/{Realm}/{dateKey}" - }; - return config; - } + return $"{Url}/{Realm}/{dateKey}"; + } +} - public static FirebaseClient CreateClient() - { - return new FirebaseClient(BuildConfig()); - } - } - - public class ReportingTest +public class ReportingTest +{ + private static readonly JsonSerializerOptions JsonOptions = new() { WriteIndented = true }; + private static readonly string resultsFileName = typeof(TTestClass).Name + ".json"; + private static string resultsFile; + private static List tests; + + [OneTimeSetUp] + public async Task ClearLocalResults() { - private static readonly string resultsFileName = typeof(TTestClass).Name + ".json"; - private static string resultsFile; - private static List tests; + resultsFile = Path.Combine(TestContext.CurrentContext.TestDirectory, resultsFileName); + tests = await LoadResults(); + } - [OneTimeSetUp] - public void ClearLocalResults() + [TearDown] + public static void WriteLastRunResult() + { + var test = TestContext.CurrentContext.Test; + var status = TestContext.CurrentContext.Result.Outcome.Status; + var succeeded = status == TestStatus.Passed; + var testName = test.Name; + if (!test.Name.Contains(test.MethodName)) testName = test.MethodName + " " + test.Name; + var testStatus = tests.FirstOrDefault(t => t.TestName == testName); + if (testStatus != null) { - resultsFile = Path.Combine(TestContext.CurrentContext.TestDirectory, resultsFileName); - tests = LoadResults(); + testStatus.LastRunTime = DateTime.Now; + testStatus.Succeeded = succeeded; } - - [TearDown] - public static void WriteLastRunResult() - { - var test = TestContext.CurrentContext.Test; - var status = TestContext.CurrentContext.Result.Outcome.Status; - var succeeded = status == TestStatus.Passed; - var testName = test.Name; - if (!test.Name.Contains(test.MethodName)) testName = test.MethodName + " " + test.Name; - var testStatus = tests.FirstOrDefault(t => t.TestName == testName); - if (testStatus != null) + else + tests.Add(new TestCaseStatus { - testStatus.LastRunTime = DateTime.Now; - testStatus.Succeeded = succeeded; - } - else - tests.Add(new TestCaseStatus - { - FirstRunTime = DateTime.Now, - LastRunTime = DateTime.Now, - TestName = testName, - TestMethod = test.MethodName, - Succeeded = succeeded - }); - } + FirstRunTime = DateTime.Now, + LastRunTime = DateTime.Now, + TestName = testName, + TestMethod = test.MethodName, + Succeeded = succeeded + }); + } - private static void SaveResults(List tests) + private static async Task SaveResults(List tests) + { + await using var stream = new FileStream(resultsFile, FileMode.Truncate); + await JsonSerializer.SerializeAsync(stream, tests, JsonOptions); + } + + private static async Task> LoadResults() + { + try { - File.WriteAllText(resultsFile, JsonConvert.SerializeObject(tests, Formatting.Indented)); + await using var stream = new FileStream(resultsFile, FileMode.Open); + var statuses = await JsonSerializer.DeserializeAsync>(stream); + return RemoveOldNames(statuses); } - - private static List LoadResults() + catch (Exception e) { - try - { - var json = File.ReadAllText(resultsFile); - var statuses = JsonConvert.DeserializeObject>(json); - return RemoveOldNames(statuses); - } - catch (Exception e) - { - Console.WriteLine(e); - return new List(); - } + Console.WriteLine(e); + return new List(); } + } + + private static List RemoveOldNames(List statuses) + { + var names = typeof(TTestClass).GetMethods().Select(m => m.Name).ToHashSet(); + return statuses.Where(s => names.Contains(s.TestMethod)).ToList(); + } - private static List RemoveOldNames(List statuses) + [OneTimeTearDown] + public static async Task ReportResults() + { + tests = tests.OrderByDescending(t => t.LastRunTime).ThenByDescending(t => t.FirstRunTime).ToList(); + await SaveResults(tests); + var names = typeof(TTestClass).GetField("Names").GetValue(null); + Console.WriteLine(names); + foreach (var kv in tests) { - var names = new HashSet(typeof(TTestClass).GetMethods().Select(m => m.Name)); - return statuses.Where(s => names.Contains(s.TestMethod)).ToList(); + Console.WriteLine(kv.TestName); } - - [OneTimeTearDown] - public static void ReportResults() + + using (var client = Firebase.CreateClient()) { - tests = tests.OrderByDescending(t => t.LastRunTime).ThenByDescending(t => t.FirstRunTime).ToList(); - SaveResults(tests); - var names = typeof(TTestClass).GetField("Names").GetValue(null); - Console.WriteLine(names); - foreach (var kv in tests) - { - Console.WriteLine(kv.TestName); - } - - using (var client = Firebase.CreateClient()) - { - client.Set(names + "/tests", tests); - } - Console.WriteLine("reported"); + await client.Child(names + "/tests").PutAsync(tests); } + Console.WriteLine("reported"); } +} - public class TestCaseStatus - { - public string TestMethod; - public string TestName; - public DateTime FirstRunTime; - public DateTime LastRunTime; - public bool Succeeded; - } +public class TestCaseStatus +{ + public string TestMethod; + public string TestName; + public DateTime FirstRunTime; + public DateTime LastRunTime; + public bool Succeeded; } \ No newline at end of file diff --git a/Exceptions/Samples/ReportReceiver.cs b/Exceptions/Samples/ReportReceiver.cs new file mode 100644 index 0000000..7945bb1 --- /dev/null +++ b/Exceptions/Samples/ReportReceiver.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +// ReSharper disable CollectionNeverQueried.Local +// ReSharper disable FieldCanBeMadeReadOnly.Local +#pragma warning disable IDE0044 // Add readonly modifier + +namespace Exceptions.Samples; + +// Что тут не так? +public class ReportReceiver +{ + private Dictionary reportsCache = new(); + private Dictionary sendersCache = new(); + private Dictionary receiversCache = new(); + private readonly OrganizationRepo organizationsRepo; + + public ReportReceiver(OrganizationRepo organizationsRepo) + { + this.organizationsRepo = organizationsRepo; + } + + public void ReceiveReport(Report report) + { + if (!reportsCache.ContainsKey(report.Id)) + { + sendersCache.Add(report.Id, organizationsRepo.Get(report.SenderId)); + receiversCache.Add(report.Id, organizationsRepo.Get(report.ReceiverId)); + reportsCache.Add(report.Id, report); + } + } + + //... +} + + +public class OrganizationRepo +{ + public Organization Get(Guid senderId) => throw new NotImplementedException(); +} + +public class Organization +{ +} + +public record Report(Guid Id, Guid SenderId, Guid ReceiverId); \ No newline at end of file diff --git a/Exceptions/Settings.cs b/Exceptions/Settings.cs index a70a8d2..6352134 100644 --- a/Exceptions/Settings.cs +++ b/Exceptions/Settings.cs @@ -1,19 +1,6 @@ -namespace Exceptions -{ - public class Settings - { - public static Settings Default = new Settings("ru", false); - public string SourceCultureName; - public bool Verbose; - - public Settings() - { - } +namespace Exceptions; - private Settings(string sourceCultureName, bool verbose) - { - SourceCultureName = sourceCultureName; - Verbose = verbose; - } - } +public record Settings(string SourceCultureName, bool Verbose) +{ + public static readonly Settings Default = new("ru", false); } \ No newline at end of file diff --git a/Exceptions/Solved/Converter_Solved.cs b/Exceptions/Solved/Converter_Solved.cs new file mode 100644 index 0000000..287eb39 --- /dev/null +++ b/Exceptions/Solved/Converter_Solved.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text.Json; +using System.Threading; +using System.Threading.Tasks; +using NLog; + +namespace Exceptions.Solved; + +public class Converter +{ + private static readonly Logger log = LogManager.GetCurrentClassLogger(); + + public static void ConvertFiles(params string[] filenames) + { + ErrorHandler.LogErrors(() => + { + filenames = filenames.Length > 0 ? filenames : new[] { "text.txt" }; + var settings = LoadSettings(); + ConvertFiles(filenames, settings); + }); + } + + private static void ConvertFiles(string[] filenames, Settings settings) + { + var tasks = filenames + .Select(fn => Task.Run(() => ConvertFile(fn, settings)) + .ContinueWith(LogIfException)) + .ToArray(); + Task.WaitAll(tasks); + } + + private static void LogIfException(Task task) + { + var exceptions = task.Exception; + if (!task.IsFaulted || exceptions == null) return; + foreach (var ex in exceptions.InnerExceptions) + log.Error(ex); + } + + private static Settings LoadSettings() + { + var filename = "settings.json"; + if (!File.Exists(filename)) + { + log.Info($"Файл настроек {filename} отсутствует. Используются настройки по умолчанию."); + return Settings.Default; + } + try + { + using var stream = new FileStream(filename, FileMode.Open); + return JsonSerializer.Deserialize(stream); + } + catch (Exception e) + { + throw new FormatException($"Не удалось прочитать файл настроек {filename}", e); + } + } + + private static void ConvertFile(string filename, Settings settings) + { + Thread.CurrentThread.CurrentCulture = new CultureInfo(settings.SourceCultureName); + if (settings.Verbose) + { + log.Info("Processing file " + filename); + log.Info("Source Culture " + Thread.CurrentThread.CurrentCulture.Name); + } + var lines = PrepareLines(filename); + try + { + var convertedLines = lines + .Select(ConvertLine) + .Select(s => s.Length + " " + s); + File.WriteAllLines(filename + ".out", convertedLines); + } + catch (Exception e) + { + throw new Exception($"Не удалось сконвертировать {filename}", e); + } + } + + private static IEnumerable PrepareLines(string filename) + { + var lineIndex = 0; + foreach (var line in File.ReadLines(filename)) + { + if (line == string.Empty) continue; + yield return line.Trim(); + lineIndex++; + } + yield return lineIndex.ToString(); + } + + public static string ConvertLine(string line) + { + return ErrorHandler.Refine(() => + TryConvertAsDateTime(line) + ?? TryConvertAsDouble(line) + ?? ConvertAsCharIndexInstruction(line), + e => new FormatException($"Некорректная строка [{line}]", e)); + } + + private static string ConvertAsCharIndexInstruction(string s) + { + var parts = s.Split(); + var charIndex = int.Parse(parts[0]); + var text = parts[1]; + return text[charIndex].ToString(); + } + + private static string TryConvertAsDateTime(string arg) + { + return DateTime.TryParse(arg, out var res) + ? res.ToString(CultureInfo.InvariantCulture) + : null; + } + + private static string TryConvertAsDouble(string arg) + { + return double.TryParse(arg, out var res) + ? res.ToString(CultureInfo.InvariantCulture) + : null; + } +} \ No newline at end of file diff --git a/Exceptions/Solved/ErrorHandler.cs b/Exceptions/Solved/ErrorHandler.cs index d580e37..10b88eb 100644 --- a/Exceptions/Solved/ErrorHandler.cs +++ b/Exceptions/Solved/ErrorHandler.cs @@ -1,35 +1,33 @@ using System; using NLog; -namespace Exceptions.Solved +namespace Exceptions.Solved; + +public static class ErrorHandler { - public static class ErrorHandler + private static readonly Logger log = LogManager.GetLogger("global"); + public static void LogErrors(Action action) { - private static readonly Logger log = LogManager.GetLogger("global"); - public static void LogErrors(Action action) + try { - try - { - action(); - } - catch (Exception e) - { - log.Error(e); - } + action(); } - - public static T Refine(Func func, - Func createRefinedError) + catch (Exception e) { - try - { - return func(); - } - catch (Exception e) - { - throw createRefinedError(e); - } + log.Error(e); } + } + public static T Refine(Func func, + Func createRefinedError) + { + try + { + return func(); + } + catch (Exception e) + { + throw createRefinedError(e); + } } } \ No newline at end of file diff --git a/Exceptions/Solved/Program_Solved.cs b/Exceptions/Solved/Program_Solved.cs deleted file mode 100644 index 2db4945..0000000 --- a/Exceptions/Solved/Program_Solved.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using System.Xml.Serialization; -using NLog; - -namespace Exceptions.Solved -{ - public class Program - { - private static readonly Logger log = LogManager.GetCurrentClassLogger(); - - public static void Main(string[] args) - { - ErrorHandler.LogErrors(() => - { - var filenames = args.Any() ? args : new[] { "text.txt" }; - var settings = LoadSettings(); - ConvertFiles(filenames, settings); - }); - } - - private static void ConvertFiles(string[] filenames, Settings settings) - { - var tasks = filenames - .Select(fn => Task.Run(() => ConvertFile(fn, settings)) - .ContinueWith(LogIfException)) - .ToArray(); - Task.WaitAll(tasks); - } - - private static void LogIfException(Task task) - { - var exceptions = task.Exception; - if (!task.IsFaulted || exceptions == null) return; - foreach (var ex in exceptions.InnerExceptions) - log.Error(ex); - } - - private static Settings LoadSettings() - { - var serializer = new XmlSerializer(typeof(Settings)); - var filename = "settings.xml"; - if (!File.Exists(filename)) - { - log.Info($"Файл настроек {filename} отсутствует. Используются настройки по умолчанию."); - return Settings.Default; - } - try - { - var content = File.ReadAllText(filename); - return (Settings)serializer.Deserialize(new StringReader(content)); - } - catch (Exception e) - { - throw new FormatException($"Не удалось прочитать файл настроек {filename}", e); - } - } - - private static void ConvertFile(string filename, Settings settings) - { - Thread.CurrentThread.CurrentCulture = new CultureInfo(settings.SourceCultureName); - if (settings.Verbose) - { - log.Info("Processing file " + filename); - log.Info("Source Culture " + Thread.CurrentThread.CurrentCulture.Name); - } - var lines = PrepareLines(filename); - try - { - var convertedLines = lines - .Select(ConvertLine) - .Select(s => s.Length + " " + s); - File.WriteAllLines(filename + ".out", convertedLines); - } - catch (Exception e) - { - throw new Exception($"Не удалось сконвертировать {filename}", e); - } - } - - private static IEnumerable PrepareLines(string filename) - { - var lineIndex = 0; - foreach (var line in File.ReadLines(filename)) - { - if (line == "") continue; - yield return line.Trim(); - lineIndex++; - } - yield return lineIndex.ToString(); - } - - private static string ConvertLine(string line) - { - return ErrorHandler.Refine(() => - TryConvertAsDateTime(line) - ?? TryConvertAsDouble(line) - ?? ConvertAsCharIndexInstruction(line), - e => new FormatException($"Некорректная строка [{line}]", e)); - } - - private static string ConvertAsCharIndexInstruction(string s) - { - var parts = s.Split(); - var charIndex = int.Parse(parts[0]); - var text = parts[1]; - return text[charIndex].ToString(); - } - - private static string TryConvertAsDateTime(string arg) - { - DateTime res; - return DateTime.TryParse(arg, out res) - ? res.ToString(CultureInfo.InvariantCulture) - : null; - } - - private static string TryConvertAsDouble(string arg) - { - double res; - return double.TryParse(arg, out res) - ? res.ToString(CultureInfo.InvariantCulture) - : null; - } - } -} \ No newline at end of file diff --git a/Exceptions/settings.json b/Exceptions/settings.json new file mode 100644 index 0000000..5813b82 --- /dev/null +++ b/Exceptions/settings.json @@ -0,0 +1,4 @@ +{ + "Verbose": true, + "SourceCultureName": "ru" +} \ No newline at end of file diff --git a/Exceptions/settings.xml b/Exceptions/settings.xml deleted file mode 100644 index aaece88..0000000 --- a/Exceptions/settings.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - true - ru - \ No newline at end of file