From c26169a32a95d9682f98e41c8f7078bf706e7e7c Mon Sep 17 00:00:00 2001 From: konstantin Date: Thu, 5 Sep 2024 14:04:12 +0200 Subject: [PATCH] fmt: use file-scoped namespaces everywhere (#519) Co-authored-by: Konstantin --- .../BenachrichtigungExtension.cs | 201 ++- .../BusinessObjects/BusinessObject.cs | 25 +- .../Energiemenge/EnergiemengeExtension.cs | 1339 ++++++++--------- .../EnergiemengeExtensionCompleteness.cs | 453 +++--- .../EnergiemengeExtensionPlausibility.cs | 391 +++-- .../EnergiemengeExtensionSlicingHelper.cs | 295 ++-- BO4E.Extensions/COM/COM.cs | 25 +- .../COM/PhysikalischerWertExtension.cs | 29 +- BO4E.Extensions/COM/VerbrauchExtension.cs | 679 +++++---- BO4E.Extensions/COM/ZeitraumExtension.cs | 27 +- .../ENUM/MengeneinheitExtension.cs | 219 ++- BO4E.Reporting/CompletenessReport.cs | 531 ++++--- BO4E.Reporting/PlausibilityReport.cs | 143 +- BO4E.Reporting/Report.cs | 477 +++--- BO4ETestProject/CreateTimeZoneJson.cs | 49 +- .../TestAbstractDeserialization.cs | 161 +- BO4ETestProject/TestAutoNumberConverter.cs | 29 +- BO4ETestProject/TestBOCOMDesign.cs | 243 ++- BO4ETestProject/TestBOCOMGuids.cs | 93 +- BO4ETestProject/TestBo4eUri.cs | 371 +++-- BO4ETestProject/TestBoExpansion.cs | 57 +- BO4ETestProject/TestEnergiemengeAdding.cs | 101 +- .../TestEnergyIdentificationCodeExtensions.cs | 149 +- BO4ETestProject/TestEnumMembers.cs | 105 +- BO4ETestProject/TestExterneReferenzen.cs | 73 +- .../TestGeraetemerkmalConverter.cs | 265 ++-- BO4ETestProject/TestJsonOrder.cs | 271 ++-- BO4ETestProject/TestJsonSchemaGeneration.cs | 89 +- BO4ETestProject/TestMaLoMeLoId.cs | 103 +- BO4ETestProject/TestMultiLangJson.cs | 235 ++- BO4ETestProject/TestNotizDeserialization.cs | 35 +- BO4ETestProject/TestNullable.cs | 65 +- BO4ETestProject/TestProtoFileGeneration.cs | 83 +- BO4ETestProject/TestProtobufAttributes.cs | 457 +++--- BO4ETestProject/TestSperrauftrag.cs | 201 ++- BO4ETestProject/TestStringEnumConverter.cs | 635 ++++---- BO4ETestProject/TestUserProperties.cs | 429 +++--- .../TestZeitraumDeserialization.cs | 73 +- .../EnergiemengeShowCaseTests.cs | 79 +- .../ShowCaseTests/VerbrauchShowCaseTests.cs | 77 +- .../TestBenachrichtigungExtension.cs | 107 +- TestBO4E.Extensions/TestCloningExtension.cs | 91 +- .../TestEnergiemengeExtension.cs | 59 +- .../TestEnergiemengeExtensionCompleteness.cs | 621 ++++---- .../TestEnergiemengeExtensionPlausibility.cs | 43 +- .../TestMengeneinheitExtension.cs | 67 +- TestBO4E.Extensions/TestVerbrauchExtension.cs | 685 +++++---- .../CompletenessReportShowCaseTests.cs | 65 +- .../TestCompletenessReportSorting.cs | 91 +- TestBO4E.Reporting/TestReportToCsv.cs | 495 +++--- 50 files changed, 5818 insertions(+), 5868 deletions(-) diff --git a/BO4E.Extensions/BusinessObjects/Benachrichtigung/BenachrichtigungExtension.cs b/BO4E.Extensions/BusinessObjects/Benachrichtigung/BenachrichtigungExtension.cs index c35959c9..ac34b539 100644 --- a/BO4E.Extensions/BusinessObjects/Benachrichtigung/BenachrichtigungExtension.cs +++ b/BO4E.Extensions/BusinessObjects/Benachrichtigung/BenachrichtigungExtension.cs @@ -4,132 +4,131 @@ using System.Linq; using BO4E.COM; -namespace BO4E.Extensions.BusinessObjects.Benachrichtigung +namespace BO4E.Extensions.BusinessObjects.Benachrichtigung; + +/// Additional methods for . +public static class BenachrichtigungExtension { - /// Additional methods for . - public static class BenachrichtigungExtension + /// + /// checks if contains a key value pair + /// + /// + /// + /// + /// + public static bool Has(this BO.Benachrichtigung b, string key, string value) { - /// - /// checks if contains a key value pair - /// - /// - /// - /// - /// - public static bool Has(this BO.Benachrichtigung b, string key, string value) + return Has(b, new GenericStringStringInfo { - return Has(b, new GenericStringStringInfo - { - KeyColumn = key, - Value = value - }); - } + KeyColumn = key, + Value = value + }); + } - /// - /// checks if contains a key value pair specified in in - /// - /// - /// - /// - /// - public static bool Has(this BO.Benachrichtigung b, GenericStringStringInfo gssi) + /// + /// checks if contains a key value pair specified in in + /// + /// + /// + /// + /// + public static bool Has(this BO.Benachrichtigung b, GenericStringStringInfo gssi) + { + if (b.Infos == null || b.Infos.Count == 0) { - if (b.Infos == null || b.Infos.Count == 0) - { - return false; - } - - // ToDo für Hamid: Bitte prüfen, warum Contains false zurückliefert. - return b.Infos.Any(m => m.KeyColumn == gssi.KeyColumn && m.Value == gssi.Value); + return false; } - /// - /// check if a specific info exists - /// - /// Benachrichtigung - /// key to be checked - /// true if key is in - public static bool Has(this BO.Benachrichtigung b, string key) - { - if (b.Infos == null || b.Infos.Count == 0) - { - return false; - } + // ToDo für Hamid: Bitte prüfen, warum Contains false zurückliefert. + return b.Infos.Any(m => m.KeyColumn == gssi.KeyColumn && m.Value == gssi.Value); + } - return b.Infos.Any(gssi => gssi.KeyColumn == key); + /// + /// check if a specific info exists + /// + /// Benachrichtigung + /// key to be checked + /// true if key is in + public static bool Has(this BO.Benachrichtigung b, string key) + { + if (b.Infos == null || b.Infos.Count == 0) + { + return false; } - /// - /// checks if Benachrichtigung has an entry with key in - /// which fulfills a predicate - /// - /// expected type of the info property - /// Benachrichtigung object - /// key name of the info property - /// - /// defines default behaviour, e.g. if no such key is present - /// allows to provide an explicit type converter - /// - /// true if there's an info object with given key of type - /// fulfilling or there's no such property but is true - /// - public static bool Has(this BO.Benachrichtigung b, string keyName, Predicate predicate, - bool passByDefault = true, TypeConverter typeConverter = null) where T : IComparable + return b.Infos.Any(gssi => gssi.KeyColumn == key); + } + + /// + /// checks if Benachrichtigung has an entry with key in + /// which fulfills a predicate + /// + /// expected type of the info property + /// Benachrichtigung object + /// key name of the info property + /// + /// defines default behaviour, e.g. if no such key is present + /// allows to provide an explicit type converter + /// + /// true if there's an info object with given key of type + /// fulfilling or there's no such property but is true + /// + public static bool Has(this BO.Benachrichtigung b, string keyName, Predicate predicate, + bool passByDefault = true, TypeConverter typeConverter = null) where T : IComparable + { + if (!b.Has(keyName)) { - if (!b.Has(keyName)) - { - return passByDefault; - } + return passByDefault; + } - foreach (var info in b.Infos.Where(gssi => gssi.KeyColumn == keyName)) - try + foreach (var info in b.Infos.Where(gssi => gssi.KeyColumn == keyName)) + try + { + if (typeConverter == null) { - if (typeConverter == null) - { - typeConverter = TypeDescriptor.GetConverter(typeof(T)); - } - - { - var value = (T)typeConverter.ConvertFromString(info.Value); - return predicate(value); - } + typeConverter = TypeDescriptor.GetConverter(typeof(T)); } - catch (NotSupportedException) + { + var value = (T)typeConverter.ConvertFromString(info.Value); + return predicate(value); } + } + catch (NotSupportedException) + { + } - return false; - } + return false; + } - /// - /// moves key value pairs from to - /// for more convenient handling. - /// - /// Benachrichtigung - /// set true to overwrite userProperties with same key - // ToDo: make method generic MoveInfosTouserProperties(...) - public static void MoveInfosToUserProperties(this BO.Benachrichtigung b, bool overwriteExistingKeys = false) + /// + /// moves key value pairs from to + /// for more convenient handling. + /// + /// Benachrichtigung + /// set true to overwrite userProperties with same key + // ToDo: make method generic MoveInfosTouserProperties(...) + public static void MoveInfosToUserProperties(this BO.Benachrichtigung b, bool overwriteExistingKeys = false) + { + if (b.Infos != null && b.Infos.Count > 0) { - if (b.Infos != null && b.Infos.Count > 0) + if (b.UserProperties == null) { - if (b.UserProperties == null) - { - b.UserProperties = new Dictionary(); - } + b.UserProperties = new Dictionary(); + } - foreach (var info in b.Infos) + foreach (var info in b.Infos) + { + if (b.UserProperties.ContainsKey(info.KeyColumn) && overwriteExistingKeys) { - if (b.UserProperties.ContainsKey(info.KeyColumn) && overwriteExistingKeys) - { - b.UserProperties.Remove(info.KeyColumn); - } - - b.UserProperties.Add(info.KeyColumn, - info.Value); // might throw exception if key exists and !overwriteExistingKeys. That's ok. + b.UserProperties.Remove(info.KeyColumn); } - b.Infos = null; // set to null after all elements have been moved + b.UserProperties.Add(info.KeyColumn, + info.Value); // might throw exception if key exists and !overwriteExistingKeys. That's ok. } + + b.Infos = null; // set to null after all elements have been moved } } } \ No newline at end of file diff --git a/BO4E.Extensions/BusinessObjects/BusinessObject.cs b/BO4E.Extensions/BusinessObjects/BusinessObject.cs index 1b446cb1..fa70540c 100644 --- a/BO4E.Extensions/BusinessObjects/BusinessObject.cs +++ b/BO4E.Extensions/BusinessObjects/BusinessObject.cs @@ -1,22 +1,21 @@ using BO4E.BO; using Newtonsoft.Json; -namespace BO4E.Extensions.BusinessObjects +namespace BO4E.Extensions.BusinessObjects; + +/// +/// common extensions for all BusinessObjects +/// +public static class BusinessObjectExtensions { /// - /// common extensions for all BusinessObjects + /// Create a deep copy of a Business Object /// - public static class BusinessObjectExtensions + /// Type of the BusinessObject + /// the BO that is copied + /// the deep copy + public static T DeepClone(this T source) where T : BusinessObject { - /// - /// Create a deep copy of a Business Object - /// - /// Type of the BusinessObject - /// the BO that is copied - /// the deep copy - public static T DeepClone(this T source) where T : BusinessObject - { - return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(source)); - } + return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(source)); } } \ No newline at end of file diff --git a/BO4E.Extensions/BusinessObjects/Energiemenge/EnergiemengeExtension.cs b/BO4E.Extensions/BusinessObjects/Energiemenge/EnergiemengeExtension.cs index 2c256b02..fbdf07ef 100644 --- a/BO4E.Extensions/BusinessObjects/Energiemenge/EnergiemengeExtension.cs +++ b/BO4E.Extensions/BusinessObjects/Energiemenge/EnergiemengeExtension.cs @@ -13,833 +13,832 @@ using static BO4E.Extensions.COM.VerbrauchExtension; -namespace BO4E.Extensions.BusinessObjects.Energiemenge +namespace BO4E.Extensions.BusinessObjects.Energiemenge; + +/// Do calculations on top of an Energiemenge BO4E. +public static partial class EnergiemengeExtension { - /// Do calculations on top of an Energiemenge BO4E. - public static partial class EnergiemengeExtension - { - private const decimal QUASI_ZERO = 0.00000000001M; + private const decimal QUASI_ZERO = 0.00000000001M; - private const string SAP_SANITIZED_USERPROPERTY_KEY = "sapSanitized"; + private const string SAP_SANITIZED_USERPROPERTY_KEY = "sapSanitized"; - private static readonly Func> PurityGrouper = - v => new Tuple(v.Wertermittlungsverfahren, v.Einheit, - v.Obiskennzahl); + private static readonly Func> PurityGrouper = + v => new Tuple(v.Wertermittlungsverfahren, v.Einheit, + v.Obiskennzahl); - /// - /// Get Zeitraum covered by Energiemenge. - /// - /// Energiemenge - /// - /// Zeitraum ranging from the earliest to the latest - /// - /// - public static Zeitraum GetZeitraum(this BO.Energiemenge menge) + /// + /// Get Zeitraum covered by Energiemenge. + /// + /// Energiemenge + /// + /// Zeitraum ranging from the earliest to the latest + /// + /// + public static Zeitraum GetZeitraum(this BO.Energiemenge menge) + { + var zeitraum = new Zeitraum { - var zeitraum = new Zeitraum - { - Startdatum = GetMinDate(menge), - Enddatum = GetMaxDate(menge) - }; - return zeitraum; - } + Startdatum = GetMinDate(menge), + Enddatum = GetMaxDate(menge) + }; + return zeitraum; + } - /// - /// Get TimeRange covered by Energiemenge - /// - /// Energiemenge - /// - /// TimeRange ranging from the earliest to the latest - /// - /// - /// - public static TimeRange GetTimeRange(this BO.Energiemenge menge) - { - return new TimeRange(menge.GetMinDate().UtcDateTime, menge.GetMaxDate().UtcDateTime); - } + /// + /// Get TimeRange covered by Energiemenge + /// + /// Energiemenge + /// + /// TimeRange ranging from the earliest to the latest + /// + /// + /// + public static TimeRange GetTimeRange(this BO.Energiemenge menge) + { + return new TimeRange(menge.GetMinDate().UtcDateTime, menge.GetMaxDate().UtcDateTime); + } + + + /* + * If GetMinDate() or GetMaxDate() throws an InvalidOperationException you shouldn't catch + * it here but allow the programmer to handle it higher up in the stack trace. + * This usually happens if one tries to use the auto-configuration feature but the + * Energieverbrauch array is empty. The result is simply undefined. Returning null + * would require all dependent methods to properly handle the null value. Since this + * would probably lead to unspecific NullReferenceExceptions we'd better let the invalid + * operation exception bubble up from here as far as it's required. + */ + private static DateTimeOffset GetMinDate(this BO.Energiemenge em) + { + return em.Energieverbrauch.Min(ev => ev.Startdatum ?? DateTimeOffset.MinValue); // don't catch! + } + + private static DateTimeOffset GetMaxDate(this BO.Energiemenge em) + { + return em.Energieverbrauch.Max(ev => ev.Enddatum ?? DateTimeOffset.MaxValue); // don't catch! + } + + /// + /// Same as + /// + /// but without auto-detected parameters. + /// By default a the full length of the Energiemenge is taken into account. + /// + /// Energiemenge + /// Tuple of consumption value and unit of measurement + public static Tuple GetTotalConsumption(this BO.Energiemenge em) + { + return GetConsumption(em, new TimeRange(em.GetMinDate().UtcDateTime, em.GetMaxDate().UtcDateTime)); + } + /// + /// Get total consumption for given parameters + /// + /// Energiemenge + /// type of measurement + /// OBIS + /// unit of measurement + /// consumption value + public static decimal GetTotalConsumption(this BO.Energiemenge em, + Wertermittlungsverfahren wev, string obiskennzahl, Mengeneinheit me) + { + return em.GetConsumption(em.GetTimeRange(), wev, obiskennzahl, me); + } - /* - * If GetMinDate() or GetMaxDate() throws an InvalidOperationException you shouldn't catch - * it here but allow the programmer to handle it higher up in the stack trace. - * This usually happens if one tries to use the auto-configuration feature but the - * Energieverbrauch array is empty. The result is simply undefined. Returning null - * would require all dependent methods to properly handle the null value. Since this - * would probably lead to unspecific NullReferenceExceptions we'd better let the invalid - * operation exception bubble up from here as far as it's required. - */ - private static DateTimeOffset GetMinDate(this BO.Energiemenge em) + /// + /// Get consumption in given time reference frame. + /// + /// Energiemenge + /// time reference frame + /// Tuple of consumption value and automatically determined unit of measurement + public static Tuple GetConsumption(this BO.Energiemenge em, ITimeRange reference) + { + if (!IsPure(em)) { - return em.Energieverbrauch.Min(ev => ev.Startdatum ?? DateTimeOffset.MinValue); // don't catch! + throw new ArgumentException("The Energiemenge is not pure."); } - private static DateTimeOffset GetMaxDate(this BO.Energiemenge em) + if (em.Energieverbrauch.Count == 0) { - return em.Energieverbrauch.Max(ev => ev.Enddatum ?? DateTimeOffset.MaxValue); // don't catch! + return Tuple.Create(0.0M, Mengeneinheit.ANZAHL); } - /// - /// Same as - /// - /// but without auto-detected parameters. - /// By default a the full length of the Energiemenge is taken into account. - /// - /// Energiemenge - /// Tuple of consumption value and unit of measurement - public static Tuple GetTotalConsumption(this BO.Energiemenge em) - { - return GetConsumption(em, new TimeRange(em.GetMinDate().UtcDateTime, em.GetMaxDate().UtcDateTime)); + ISet einheiten = new HashSet(em.Energieverbrauch.Select(x => x.Einheit)); + if (einheiten.Count > 1) + // z.B. kWh und Wh oder Monat und Jahr... Die liefern IsPure==true. + { + throw new NotImplementedException("Converting different units of same type is not supported yet."); } - /// - /// Get total consumption for given parameters - /// - /// Energiemenge - /// type of measurement - /// OBIS - /// unit of measurement - /// consumption value - public static decimal GetTotalConsumption(this BO.Energiemenge em, - Wertermittlungsverfahren wev, string obiskennzahl, Mengeneinheit me) - { - return em.GetConsumption(em.GetTimeRange(), wev, obiskennzahl, me); - } + var v = em.Energieverbrauch.First(); + var consumption = em.GetConsumption(reference, v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit); + return Tuple.Create(consumption, v.Einheit); + + } - /// - /// Get consumption in given time reference frame. - /// - /// Energiemenge - /// time reference frame - /// Tuple of consumption value and automatically determined unit of measurement - public static Tuple GetConsumption(this BO.Energiemenge em, ITimeRange reference) + /// + /// Returns the consumption of a given kind of Mengeneinheit within the specified reference time range. + /// + /// Energiemenge + /// reference time frame + /// Wertermittlungsverfahren + /// OBIS number + /// an extensive unit (e.g. "kWh") + /// + /// the consumption within the give time slice in the unit passed as + /// + /// + public static decimal GetConsumption(this BO.Energiemenge em, ITimeRange reference, + Wertermittlungsverfahren? wev, string obiskennzahl, Mengeneinheit me) + { + if (!me.IsExtensive()) { - if (!IsPure(em)) - { - throw new ArgumentException("The Energiemenge is not pure."); - } + throw new ArgumentException( + $"The Mengeneinheit {me} isn't extensive. Calculating a consumption doesn't make sense."); + } - if (em.Energieverbrauch.Count == 0) - { - return Tuple.Create(0.0M, Mengeneinheit.ANZAHL); - } + return em.Energieverbrauch + .Where(v => v.Wertermittlungsverfahren == wev && v.Obiskennzahl == obiskennzahl && v.Einheit == me) + .Sum(v => GetOverlapFactor(new TimeRange((v.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v.Enddatum ?? DateTimeOffset.MinValue).DateTime), reference, false) * v.Wert); + } - ISet einheiten = new HashSet(em.Energieverbrauch.Select(x => x.Einheit)); - if (einheiten.Count > 1) - // z.B. kWh und Wh oder Monat und Jahr... Die liefern IsPure==true. - { - throw new NotImplementedException("Converting different units of same type is not supported yet."); - } + /// + /// normalise energiemenge->energieverbrauch consumption values to a given value + /// + /// Energiemenge + /// normalising constant (1.0 by default) + /// new Energiemenge object with normalised consumption values + public static BO.Energiemenge Normalise(this BO.Energiemenge em, decimal target = 1.0M) + { - var v = em.Energieverbrauch.First(); - var consumption = em.GetConsumption(reference, v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit); - return Tuple.Create(consumption, v.Einheit); + BO.Energiemenge result; + decimal scalingFactor; + Tuple totalConsumption; + totalConsumption = em.GetTotalConsumption(); + result = em.DeepClone(); + if (totalConsumption.Item1 != 0.0M) + { + scalingFactor = target / totalConsumption.Item1; + } + else + { + scalingFactor = 0.0M; } - /// - /// Returns the consumption of a given kind of Mengeneinheit within the specified reference time range. - /// - /// Energiemenge - /// reference time frame - /// Wertermittlungsverfahren - /// OBIS number - /// an extensive unit (e.g. "kWh") - /// - /// the consumption within the give time slice in the unit passed as - /// - /// - public static decimal GetConsumption(this BO.Energiemenge em, ITimeRange reference, - Wertermittlungsverfahren? wev, string obiskennzahl, Mengeneinheit me) - { - if (!me.IsExtensive()) - { - throw new ArgumentException( - $"The Mengeneinheit {me} isn't extensive. Calculating a consumption doesn't make sense."); - } + Parallel.ForEach(result.Energieverbrauch.Where(v => v.Einheit == totalConsumption.Item2), + v => { v.Wert = scalingFactor * v.Wert; }); - return em.Energieverbrauch - .Where(v => v.Wertermittlungsverfahren == wev && v.Obiskennzahl == obiskennzahl && v.Einheit == me) - .Sum(v => GetOverlapFactor(new TimeRange((v.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v.Enddatum ?? DateTimeOffset.MinValue).DateTime), reference, false) * v.Wert); - } - /// - /// normalise energiemenge->energieverbrauch consumption values to a given value - /// - /// Energiemenge - /// normalising constant (1.0 by default) - /// new Energiemenge object with normalised consumption values - public static BO.Energiemenge Normalise(this BO.Energiemenge em, decimal target = 1.0M) - { + return result; - BO.Energiemenge result; - decimal scalingFactor; - Tuple totalConsumption; + } + + /// + /// Returns the load in an intensive unit for a given point in time. + /// + /// Energiemenge + /// an intensive unit (e.g. "kW") + /// point in time + /// load if Energiemenge BO contains value for specified date time, null otherwise + public static decimal? GetLoad(this BO.Energiemenge em, Mengeneinheit me, DateTime dt) + { + if (!me.IsIntensive()) + { + throw new ArgumentException( + $"The Mengeneinheit {me} isn't intensive. Calculating the value for a specific point in time doesn't make sense."); + } - totalConsumption = em.GetTotalConsumption(); - result = em.DeepClone(); - if (totalConsumption.Item1 != 0.0M) + decimal? result = null; + foreach (var v in em.Energieverbrauch.Where(v => v.Startdatum <= dt && dt < v.Enddatum)) + if (result.HasValue) { - scalingFactor = target / totalConsumption.Item1; + result += v.Wert; } else { - scalingFactor = 0.0M; + result = v.Wert; } - Parallel.ForEach(result.Energieverbrauch.Where(v => v.Einheit == totalConsumption.Item2), - v => { v.Wert = scalingFactor * v.Wert; }); - - - return result; + return result; + } + /// + /// Get Average ( + /// ) + /// for a pure Energiemenge with automatically found parameters. + /// + /// + /// Energiemenge + /// Tuple of average value and unit of measurement + public static Tuple GetAverage(this BO.Energiemenge em) + { + if (!IsPure(em)) + { + throw new ArgumentException("Energiemenge is not pure."); } - /// - /// Returns the load in an intensive unit for a given point in time. - /// - /// Energiemenge - /// an intensive unit (e.g. "kW") - /// point in time - /// load if Energiemenge BO contains value for specified date time, null otherwise - public static decimal? GetLoad(this BO.Energiemenge em, Mengeneinheit me, DateTime dt) + if (em.Energieverbrauch.Count == 0) { - if (!me.IsIntensive()) - { - throw new ArgumentException( - $"The Mengeneinheit {me} isn't intensive. Calculating the value for a specific point in time doesn't make sense."); - } + return Tuple.Create(null, Mengeneinheit.KW); + } - decimal? result = null; - foreach (var v in em.Energieverbrauch.Where(v => v.Startdatum <= dt && dt < v.Enddatum)) - if (result.HasValue) - { - result += v.Wert; - } - else - { - result = v.Wert; - } + var v = em.Energieverbrauch.First(); + return Tuple.Create(em.GetAverage(v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit), v.Einheit); + } - return result; - } + /// + /// Same as but without specifying a time slice. + /// + /// Energiemenge + /// type of measurement + /// OBIS + /// an intensive or extensive unit + /// + /// The average for the given Mengeneinheit for the Energiemenge object or null if there was no Verbrauch for the + /// given Mengeneinheit. + /// + public static decimal? GetAverage(this BO.Energiemenge em, + Wertermittlungsverfahren? wev, string obiskennzahl, Mengeneinheit me) + { + return em.GetAverage(em.GetTimeRange(), wev, obiskennzahl, me); + } - /// - /// Get Average ( - /// ) - /// for a pure Energiemenge with automatically found parameters. - /// - /// - /// Energiemenge - /// Tuple of average value and unit of measurement - public static Tuple GetAverage(this BO.Energiemenge em) - { - if (!IsPure(em)) + /// + /// Get average of Mengeneinheit for given time interval + /// + /// Energiemenge + /// reference time frame + /// Wertermittlungsverfahren + /// OBIS + /// an extensive or intensive unit + /// the average value or null if no Verbrauch overlapped with the specified time interval + public static decimal? GetAverage(this BO.Energiemenge em, TimeRange reference, + Wertermittlungsverfahren? wev, string obiskennzahl, Mengeneinheit me) + { + decimal? result = null; + var overallDenominator = 0.0M; + foreach (var v in em.Energieverbrauch.Where(v => v.Einheit == me)) + { + var overlapFactor = GetOverlapFactor(new TimeRange((v.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v.Enddatum ?? DateTimeOffset.MinValue).DateTime), reference, true); + if (result.HasValue) { - throw new ArgumentException("Energiemenge is not pure."); + result += overlapFactor * v.Wert; } - - if (em.Energieverbrauch.Count == 0) + else { - return Tuple.Create(null, Mengeneinheit.KW); + result = v.Wert; } - var v = em.Energieverbrauch.First(); - return Tuple.Create(em.GetAverage(v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit), v.Einheit); + overallDenominator += overlapFactor; } - /// - /// Same as but without specifying a time slice. - /// - /// Energiemenge - /// type of measurement - /// OBIS - /// an intensive or extensive unit - /// - /// The average for the given Mengeneinheit for the Energiemenge object or null if there was no Verbrauch for the - /// given Mengeneinheit. - /// - public static decimal? GetAverage(this BO.Energiemenge em, - Wertermittlungsverfahren? wev, string obiskennzahl, Mengeneinheit me) - { - return em.GetAverage(em.GetTimeRange(), wev, obiskennzahl, me); + if (result.HasValue) + { + return result / overallDenominator; } - /// - /// Get average of Mengeneinheit for given time interval - /// - /// Energiemenge - /// reference time frame - /// Wertermittlungsverfahren - /// OBIS - /// an extensive or intensive unit - /// the average value or null if no Verbrauch overlapped with the specified time interval - public static decimal? GetAverage(this BO.Energiemenge em, TimeRange reference, - Wertermittlungsverfahren? wev, string obiskennzahl, Mengeneinheit me) - { - decimal? result = null; - var overallDenominator = 0.0M; - foreach (var v in em.Energieverbrauch.Where(v => v.Einheit == me)) - { - var overlapFactor = GetOverlapFactor(new TimeRange((v.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v.Enddatum ?? DateTimeOffset.MinValue).DateTime), reference, true); - if (result.HasValue) - { - result += overlapFactor * v.Wert; - } - else - { - result = v.Wert; - } + return null; + } - overallDenominator += overlapFactor; - } + /// + /// Get list of those time ranges within the energiemenge where there are gaps. + /// + /// Energiemenge + /// + public static IList GetMissingTimeRanges(this BO.Energiemenge em) + { + return em.GetMissingTimeRanges(em.GetTimeRange()); + } - if (result.HasValue) - { - return result / overallDenominator; - } + /// + /// Get a list of those time ranges within a reference, where no energieverbrauch entries are defined. + /// + /// Energiemenge + /// reference time frame + /// Wertermittlungsverfahren + /// OBIS-Kennzahl + /// Mengeneinheit + /// + public static List GetMissingTimeRanges(this BO.Energiemenge em, ITimeRange reference, + Wertermittlungsverfahren? wev, string obis, Mengeneinheit me) + { + + IDictionary, Verbrauch> filteredVerbrauch; + + filteredVerbrauch = em.Energieverbrauch + .Where(v => v.Wertermittlungsverfahren == wev && v.Obiskennzahl == obis && v.Einheit == me) + .ToDictionary(v => new Tuple(v.Startdatum, v.Enddatum), v => v); - return null; - } - /// - /// Get list of those time ranges within the energiemenge where there are gaps. - /// - /// Energiemenge - /// - public static IList GetMissingTimeRanges(this BO.Energiemenge em) + if (filteredVerbrauch.Count < 2) { - return em.GetMissingTimeRanges(em.GetTimeRange()); + throw new ArgumentException("Not enough entries in energieverbrauch to determine periodicity."); } - /// - /// Get a list of those time ranges within a reference, where no energieverbrauch entries are defined. - /// - /// Energiemenge - /// reference time frame - /// Wertermittlungsverfahren - /// OBIS-Kennzahl - /// Mengeneinheit - /// - public static List GetMissingTimeRanges(this BO.Energiemenge em, ITimeRange reference, - Wertermittlungsverfahren? wev, string obis, Mengeneinheit me) + if (!IsEvenlySpaced(em, reference, wev, obis, me, true)) { + throw new ArgumentException( + "The provided Energiemenge is not evenly spaced although gaps are allowed."); + } - IDictionary, Verbrauch> filteredVerbrauch; - - filteredVerbrauch = em.Energieverbrauch - .Where(v => v.Wertermittlungsverfahren == wev && v.Obiskennzahl == obis && v.Einheit == me) - .ToDictionary(v => new Tuple(v.Startdatum, v.Enddatum), v => v); + var periodicity = GetTimeSpans(em, wev, obis, me).Min(); + if ( + Math.Abs((reference.Start - em.GetMinDate()).TotalMilliseconds % periodicity.TotalMilliseconds) != + 0) + { + throw new ArgumentException( + $"The absolute difference between reference.start ({reference.Start}) and the minimal date time in the Energiemenge ({em.GetMinDate()}) has to be an integer multiple of the periodicity {periodicity.TotalMilliseconds} but was {(reference.Start - em.GetMinDate()).TotalMilliseconds}."); + } + // since it's assured, that the energieverbrauch entries are evenly spaced it doesn't matter which entry we use to determine the duration. + var duration = filteredVerbrauch.Values.Min(v => v.Enddatum) - + filteredVerbrauch.Values.Min(v => v.Startdatum); + var result = new List(); - if (filteredVerbrauch.Count < 2) + for (var dt = reference.Start; dt < reference.End; dt += periodicity) + { + // use a strict '==' instead of overlap. This is justified because all the other cases are considered beforehand + switch (dt.Kind) { - throw new ArgumentException("Not enough entries in energieverbrauch to determine periodicity."); + case DateTimeKind.Local: + throw new ArgumentException("Local DateTime not supported!"); + case DateTimeKind.Unspecified: + dt = DateTime.SpecifyKind(dt, DateTimeKind.Utc); + break; + case DateTimeKind.Utc: + break; } - if (!IsEvenlySpaced(em, reference, wev, obis, me, true)) + //using (MiniProfiler.Current.Step("linq where on filtered verbrauch")) + //{ + if (!filteredVerbrauch.ContainsKey( + new Tuple(dt, + dt + duration))) // Where(v => v.startdatum == dt && v.enddatum == dt + duration).Any()) { - throw new ArgumentException( - "The provided Energiemenge is not evenly spaced although gaps are allowed."); + result.Add(new TimeRange(dt, (dt + duration).Value)); } + //} + } - var periodicity = GetTimeSpans(em, wev, obis, me).Min(); - if ( - Math.Abs((reference.Start - em.GetMinDate()).TotalMilliseconds % periodicity.TotalMilliseconds) != - 0) - { - throw new ArgumentException( - $"The absolute difference between reference.start ({reference.Start}) and the minimal date time in the Energiemenge ({em.GetMinDate()}) has to be an integer multiple of the periodicity {periodicity.TotalMilliseconds} but was {(reference.Start - em.GetMinDate()).TotalMilliseconds}."); - } - // since it's assured, that the energieverbrauch entries are evenly spaced it doesn't matter which entry we use to determine the duration. - var duration = filteredVerbrauch.Values.Min(v => v.Enddatum) - - filteredVerbrauch.Values.Min(v => v.Startdatum); - var result = new List(); + return result; - for (var dt = reference.Start; dt < reference.End; dt += periodicity) - { - // use a strict '==' instead of overlap. This is justified because all the other cases are considered beforehand - switch (dt.Kind) - { - case DateTimeKind.Local: - throw new ArgumentException("Local DateTime not supported!"); - case DateTimeKind.Unspecified: - dt = DateTime.SpecifyKind(dt, DateTimeKind.Utc); - break; - case DateTimeKind.Utc: - break; - } + } - //using (MiniProfiler.Current.Step("linq where on filtered verbrauch")) - //{ - if (!filteredVerbrauch.ContainsKey( - new Tuple(dt, - dt + duration))) // Where(v => v.startdatum == dt && v.enddatum == dt + duration).Any()) - { - result.Add(new TimeRange(dt, (dt + duration).Value)); - } - //} - } + /// + /// + /// + /// Energiemenge + /// reference time frame + /// + public static List GetMissingTimeRanges(this BO.Energiemenge em, TimeRange reference) + { + if (!em.IsPure()) + { + throw new ArgumentException( + "The Energiemenge you provided is not pure. Consider using the overloaded method."); + } + + var v = em.Energieverbrauch.FirstOrDefault(); + return GetMissingTimeRanges(em, reference, v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit); + } + /// + /// Test, if the single entries/intervals of the energieverbrauch array share the same duration and spacing in time. + /// + /// Energiemenge + /// reference time frame + /// Wertermittlungsverfahren + /// OBIS-Kennzahl + /// Mengeneinheit + /// set true to allow gaps + /// + /// True, if all energieverbrauch entries have the same length and their start and enddatum are evenly spaced. + /// Also true, if there less than 2 entries in the energieverbrauch array. + /// + public static bool IsEvenlySpaced(this BO.Energiemenge em, ITimeRange reference, Wertermittlungsverfahren? wev, + string obis, Mengeneinheit me, bool allowGaps = false) + { + HashSet startEndDatumPeriods; - return result; + startEndDatumPeriods = GetTimeSpans(em, wev, obis, me); - } - /// - /// - /// - /// Energiemenge - /// reference time frame - /// - public static List GetMissingTimeRanges(this BO.Energiemenge em, TimeRange reference) + if (startEndDatumPeriods.Count < 2) { - if (!em.IsPure()) - { - throw new ArgumentException( - "The Energiemenge you provided is not pure. Consider using the overloaded method."); - } - - var v = em.Energieverbrauch.FirstOrDefault(); - return GetMissingTimeRanges(em, reference, v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit); + return true; } - /// - /// Test, if the single entries/intervals of the energieverbrauch array share the same duration and spacing in time. - /// - /// Energiemenge - /// reference time frame - /// Wertermittlungsverfahren - /// OBIS-Kennzahl - /// Mengeneinheit - /// set true to allow gaps - /// - /// True, if all energieverbrauch entries have the same length and their start and enddatum are evenly spaced. - /// Also true, if there less than 2 entries in the energieverbrauch array. - /// - public static bool IsEvenlySpaced(this BO.Energiemenge em, ITimeRange reference, Wertermittlungsverfahren? wev, - string obis, Mengeneinheit me, bool allowGaps = false) + if (allowGaps) { - HashSet startEndDatumPeriods; + // each time difference must be a multiple of the smallest difference. - startEndDatumPeriods = GetTimeSpans(em, wev, obis, me); + var minDiff = startEndDatumPeriods.Min().TotalSeconds; + foreach (var ts in startEndDatumPeriods) + if (Math.Abs(ts.TotalSeconds % minDiff) != 0) + // use profiler as logger: + { + return false; + } - if (startEndDatumPeriods.Count < 2) - { - return true; - } - if (allowGaps) - { - // each time difference must be a multiple of the smallest difference. + return true; + } - var minDiff = startEndDatumPeriods.Min().TotalSeconds; - foreach (var ts in startEndDatumPeriods) - if (Math.Abs(ts.TotalSeconds % minDiff) != 0) - // use profiler as logger: + // there must be only 1 time difference between all the elements + return startEndDatumPeriods.Count <= 1; + } - { - return false; - } + /// + /// + /// + /// Energiemenge + /// + /// + public static bool IsEvenlySpaced(this BO.Energiemenge em, bool allowGaps = false) + { + if (!em.IsPure()) + { + // Find all combinations of Wertermittlungsverfahren, obis and Mengeneinheit. + // The Energiemenge is evenly spaced if each of the combinations is evenly spaced itself. + var combinations = GetWevObisMeCombinations(em); + foreach (var combo in combinations) + if (!em.IsEvenlySpaced(em.GetTimeRange(), combo.Item1, combo.Item2, combo.Item3, allowGaps)) + { + return false; + } - return true; - } - // there must be only 1 time difference between all the elements - return startEndDatumPeriods.Count <= 1; + return true; } - /// - /// - /// - /// Energiemenge - /// - /// - public static bool IsEvenlySpaced(this BO.Energiemenge em, bool allowGaps = false) - { - if (!em.IsPure()) - { - // Find all combinations of Wertermittlungsverfahren, obis and Mengeneinheit. - // The Energiemenge is evenly spaced if each of the combinations is evenly spaced itself. - - var combinations = GetWevObisMeCombinations(em); - foreach (var combo in combinations) - if (!em.IsEvenlySpaced(em.GetTimeRange(), combo.Item1, combo.Item2, combo.Item3, allowGaps)) - { - return false; - } - + var v = em.Energieverbrauch.FirstOrDefault(); + return em.IsEvenlySpaced(em.GetTimeRange(), v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit, + allowGaps); + } - return true; - } - var v = em.Energieverbrauch.FirstOrDefault(); - return em.IsEvenlySpaced(em.GetTimeRange(), v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit, - allowGaps); + private static HashSet GetTimeSpans(this BO.Energiemenge em) + { + var result = new HashSet(); + var vlist = new List(em.Energieverbrauch); + vlist.Sort(new VerbrauchDateTimeComparer()); + for (var i = 1; i < vlist.Count; i++) + { + result.Add((vlist[i].Startdatum ?? DateTimeOffset.MinValue) - (vlist[i - 1].Startdatum ?? DateTimeOffset.MinValue)); + result.Add((vlist[i].Enddatum ?? DateTimeOffset.MinValue) - (vlist[i - 1].Enddatum ?? DateTimeOffset.MinValue)); } + return result; + } - private static HashSet GetTimeSpans(this BO.Energiemenge em) + private static HashSet GetTimeSpans(this BO.Energiemenge em, Wertermittlungsverfahren? wev, + string obis, Mengeneinheit me) + { + var result = new HashSet(); + var vlist = new List(em.Energieverbrauch); + vlist.Sort(new VerbrauchDateTimeComparer()); + vlist = vlist.Where(v => v.Wertermittlungsverfahren == wev && v.Obiskennzahl == obis && v.Einheit == me) + .ToList(); + for (var i = 1; i < vlist.Count; i++) { - var result = new HashSet(); - var vlist = new List(em.Energieverbrauch); - vlist.Sort(new VerbrauchDateTimeComparer()); - for (var i = 1; i < vlist.Count; i++) - { - result.Add((vlist[i].Startdatum ?? DateTimeOffset.MinValue) - (vlist[i - 1].Startdatum ?? DateTimeOffset.MinValue)); - result.Add((vlist[i].Enddatum ?? DateTimeOffset.MinValue) - (vlist[i - 1].Enddatum ?? DateTimeOffset.MinValue)); - } - - return result; + result.Add((vlist[i].Startdatum ?? DateTimeOffset.MinValue) - (vlist[i - 1].Startdatum ?? DateTimeOffset.MinValue)); + result.Add((vlist[i].Enddatum ?? DateTimeOffset.MinValue) - (vlist[i - 1].Enddatum ?? DateTimeOffset.MinValue)); } - private static HashSet GetTimeSpans(this BO.Energiemenge em, Wertermittlungsverfahren? wev, - string obis, Mengeneinheit me) - { - var result = new HashSet(); - var vlist = new List(em.Energieverbrauch); - vlist.Sort(new VerbrauchDateTimeComparer()); - vlist = vlist.Where(v => v.Wertermittlungsverfahren == wev && v.Obiskennzahl == obis && v.Einheit == me) - .ToList(); - for (var i = 1; i < vlist.Count; i++) - { - result.Add((vlist[i].Startdatum ?? DateTimeOffset.MinValue) - (vlist[i - 1].Startdatum ?? DateTimeOffset.MinValue)); - result.Add((vlist[i].Enddatum ?? DateTimeOffset.MinValue) - (vlist[i - 1].Enddatum ?? DateTimeOffset.MinValue)); - } + return result; + } - return result; - } + /// + /// get all (Wertermittlungsverfahren, OBIS, Mengeneinheit) tuples occurring in + /// + /// em + /// A Set of tuples of all (Wertermittlungsverfahren, OBIS, Mengeneinheit) combinations + public static ISet> GetWevObisMeCombinations( + this BO.Energiemenge em) + { + return new HashSet>( + em.Energieverbrauch + .Select(v => Tuple.Create(v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit))); + } - /// - /// get all (Wertermittlungsverfahren, OBIS, Mengeneinheit) tuples occurring in - /// - /// em - /// A Set of tuples of all (Wertermittlungsverfahren, OBIS, Mengeneinheit) combinations - public static ISet> GetWevObisMeCombinations( - this BO.Energiemenge em) - { - return new HashSet>( - em.Energieverbrauch - .Select(v => Tuple.Create(v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit))); - } + /// + /// Get percentage of time range covered by all Wertermittlungsverfahren/OBIS/Mengeneinheit + /// combinations, that are present in the Energiemenge->energieverbrauch array. + /// + /// Energiemenge + /// reference + /// + public static decimal GetJointCoverage(this BO.Energiemenge em, TimeRange reference) + { + var combinations = GetWevObisMeCombinations(em); + var jointCoverage = em.Energieverbrauch + .Where(v => combinations.Contains(Tuple.Create(v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit))) + .Sum(v => GetOverlapFactor(new TimeRange((v.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v.Enddatum ?? DateTimeOffset.MinValue).DateTime), reference, true)); + return jointCoverage - (combinations.Count - 1); + } - /// - /// Get percentage of time range covered by all Wertermittlungsverfahren/OBIS/Mengeneinheit - /// combinations, that are present in the Energiemenge->energieverbrauch array. - /// - /// Energiemenge - /// reference - /// - public static decimal GetJointCoverage(this BO.Energiemenge em, TimeRange reference) + /// + /// Get percentage of time range covered by pure Energiemenge. + /// + /// pure Energiemenge + /// time frame reference + /// value between 0 (only coverage for 1 point in time) and 1.0 (100% coverage) + public static decimal GetCoverage(this BO.Energiemenge em, ITimeRange reference) + { + + if (!IsPure(em)) { - var combinations = GetWevObisMeCombinations(em); - var jointCoverage = em.Energieverbrauch - .Where(v => combinations.Contains(Tuple.Create(v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit))) - .Sum(v => GetOverlapFactor(new TimeRange((v.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v.Enddatum ?? DateTimeOffset.MinValue).DateTime), reference, true)); - return jointCoverage - (combinations.Count - 1); + throw new ArgumentException("The Energiemenge is not pure. Cannot determine parameters."); } - /// - /// Get percentage of time range covered by pure Energiemenge. - /// - /// pure Energiemenge - /// time frame reference - /// value between 0 (only coverage for 1 point in time) and 1.0 (100% coverage) - public static decimal GetCoverage(this BO.Energiemenge em, ITimeRange reference) + if (em.Energieverbrauch.Count == 0) { + return 0.0M; + } - if (!IsPure(em)) - { - throw new ArgumentException("The Energiemenge is not pure. Cannot determine parameters."); - } + var v = em.Energieverbrauch.First(); + return em.GetCoverage(reference, v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit); - if (em.Energieverbrauch.Count == 0) - { - return 0.0M; - } + } - var v = em.Energieverbrauch.First(); - return em.GetCoverage(reference, v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit); + /// + /// Get percentage of full time range of energiemenge which is covered with values. + /// + /// Energiemenge + /// value between 0 (only coverage for 1 point in time) and 1.0 (100% coverage) + public static decimal GetCoverage(this BO.Energiemenge em) + { + return em.GetCoverage(em.GetTimeRange()); + } - } + /// + /// Get ratio of overlap between given Energiemenge and a reference. + /// Method is basically just another name for + /// + /// Energiemenge + /// reference time range + /// OBIS + /// unit of measurement + /// type of measurement + /// post decimals + /// value between 0 (no overlap) and 1.0 (100% overlap) + public static decimal GetCoverage(this BO.Energiemenge em, ITimeRange reference, + Wertermittlungsverfahren? wev, string obisKz, Mengeneinheit mengeneinheit, int decimalRounding = 10) + { + decimal exactResult; - /// - /// Get percentage of full time range of energiemenge which is covered with values. - /// - /// Energiemenge - /// value between 0 (only coverage for 1 point in time) and 1.0 (100% coverage) - public static decimal GetCoverage(this BO.Energiemenge em) - { - return em.GetCoverage(em.GetTimeRange()); - } + exactResult = em.Energieverbrauch + .Where(v => v.Einheit == mengeneinheit && v.Obiskennzahl == obisKz && + v.Wertermittlungsverfahren == wev) + .Sum(v => GetOverlapFactor(new TimeRange((v.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v.Enddatum ?? DateTimeOffset.MinValue).DateTime), reference, true)); - /// - /// Get ratio of overlap between given Energiemenge and a reference. - /// Method is basically just another name for - /// - /// Energiemenge - /// reference time range - /// OBIS - /// unit of measurement - /// type of measurement - /// post decimals - /// value between 0 (no overlap) and 1.0 (100% overlap) - public static decimal GetCoverage(this BO.Energiemenge em, ITimeRange reference, - Wertermittlungsverfahren? wev, string obisKz, Mengeneinheit mengeneinheit, int decimalRounding = 10) - { - decimal exactResult; - - exactResult = em.Energieverbrauch - .Where(v => v.Einheit == mengeneinheit && v.Obiskennzahl == obisKz && - v.Wertermittlungsverfahren == wev) - .Sum(v => GetOverlapFactor(new TimeRange((v.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v.Enddatum ?? DateTimeOffset.MinValue).DateTime), reference, true)); - - - return Math.Round(exactResult, decimalRounding); - } - /// - /// Test, if the Energiemenge is continuous within its own min/max range. - /// - /// - /// Energiemenge - /// - /// true iff Energiemenge has defined value for every point in time t in - /// min(energieverbrauch.startdatum) <= t < max(energieverbrauch.enddatum); - /// false otherwise - /// - public static bool IsContinuous(this BO.Energiemenge em) - { - return IsContinuous(em, new TimeRange(em.GetMinDate().UtcDateTime, em.GetMaxDate().UtcDateTime)); - } + return Math.Round(exactResult, decimalRounding); + } - /// - /// Test, if the Energiemenge does have a defined value for every point in time within the given time range. - /// - /// Energiemenge - /// time range to check - /// true iff Energiemenge has defined value for every point in time range, false otherwise - public static bool IsContinuous(this BO.Energiemenge em, TimeRange reference) - { - return Math.Abs(em.Energieverbrauch.Sum(v => - GetOverlapFactor(new TimeRange((v.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v.Enddatum ?? DateTimeOffset.MinValue).DateTime), reference, true)) - 1.0M) < QUASI_ZERO; - } + /// + /// Test, if the Energiemenge is continuous within its own min/max range. + /// + /// + /// Energiemenge + /// + /// true iff Energiemenge has defined value for every point in time t in + /// min(energieverbrauch.startdatum) <= t < max(energieverbrauch.enddatum); + /// false otherwise + /// + public static bool IsContinuous(this BO.Energiemenge em) + { + return IsContinuous(em, new TimeRange(em.GetMinDate().UtcDateTime, em.GetMaxDate().UtcDateTime)); + } - private static decimal GetOverlapFactor(TimeRange period, ITimeRange reference, bool toReference) - { - var periods = new TimePeriodCollection - { - reference, - period - }; - var periodIntersector = new TimePeriodIntersector(); - var intersectedPeriods = periodIntersector.IntersectPeriods(periods); - try - { - if (toReference) - { - return (decimal)intersectedPeriods.TotalDuration.TotalSeconds / - (decimal)reference.Duration.TotalSeconds; - } + /// + /// Test, if the Energiemenge does have a defined value for every point in time within the given time range. + /// + /// Energiemenge + /// time range to check + /// true iff Energiemenge has defined value for every point in time range, false otherwise + public static bool IsContinuous(this BO.Energiemenge em, TimeRange reference) + { + return Math.Abs(em.Energieverbrauch.Sum(v => + GetOverlapFactor(new TimeRange((v.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v.Enddatum ?? DateTimeOffset.MinValue).DateTime), reference, true)) - 1.0M) < QUASI_ZERO; + } - return (decimal)intersectedPeriods.TotalDuration.TotalSeconds / (decimal)period.Duration.TotalSeconds; - } - catch (DivideByZeroException) + private static decimal GetOverlapFactor(TimeRange period, ITimeRange reference, bool toReference) + { + var periods = new TimePeriodCollection + { + reference, + period + }; + var periodIntersector = new TimePeriodIntersector(); + var intersectedPeriods = periodIntersector.IntersectPeriods(periods); + try + { + if (toReference) { - return 0.0M; + return (decimal)intersectedPeriods.TotalDuration.TotalSeconds / + (decimal)reference.Duration.TotalSeconds; } - } - /// - /// shortcut for && && - /// - /// - /// Energiemenge - /// - /// set true, to additionally check if user properties of all entries in energieverbrauch - /// are equal. - /// - /// true iff the Energiemenge is pure in all OBIS-Kennzahl, Wertermittlungsverfahren and Mengeneinheit - public static bool IsPure(this BO.Energiemenge em, bool checkUserProperties = false) + return (decimal)intersectedPeriods.TotalDuration.TotalSeconds / (decimal)period.Duration.TotalSeconds; + } + catch (DivideByZeroException) { - bool basicPurity; + return 0.0M; + } + } - basicPurity = em.IsPureMengeneinheit() && em.IsPureObisKennzahl() && - em.IsPureWertermittlungsverfahren(); + /// + /// shortcut for && && + /// + /// + /// Energiemenge + /// + /// set true, to additionally check if user properties of all entries in energieverbrauch + /// are equal. + /// + /// true iff the Energiemenge is pure in all OBIS-Kennzahl, Wertermittlungsverfahren and Mengeneinheit + public static bool IsPure(this BO.Energiemenge em, bool checkUserProperties = false) + { + bool basicPurity; + basicPurity = em.IsPureMengeneinheit() && em.IsPureObisKennzahl() && + em.IsPureWertermittlungsverfahren(); - if (basicPurity && checkUserProperties) - { - var upPurity = em.IsPureUserProperties(); - return upPurity && basicPurity; - } - return basicPurity; + if (basicPurity && checkUserProperties) + { + var upPurity = em.IsPureUserProperties(); + return upPurity && basicPurity; } - /// - /// test if Energiemenge has only one - /// - /// Energiemenge - /// true iff the Energiemenge->energieverbrauch list has at most one distinct Wertermittlungsverfahren - public static bool IsPureWertermittlungsverfahren(this BO.Energiemenge em) - { + return basicPurity; + } - return em.Energieverbrauch.Select(v => v.Wertermittlungsverfahren).Distinct().Count() <= 1; + /// + /// test if Energiemenge has only one + /// + /// Energiemenge + /// true iff the Energiemenge->energieverbrauch list has at most one distinct Wertermittlungsverfahren + public static bool IsPureWertermittlungsverfahren(this BO.Energiemenge em) + { - } + return em.Energieverbrauch.Select(v => v.Wertermittlungsverfahren).Distinct().Count() <= 1; - /// - /// test if Energiemenge has only one Obiskennzahl - /// - /// Energiemenge - /// true iff the Energiemenge->energieverbrauch list has at most one distinct Obiskennzahl - public static bool IsPureObisKennzahl(this BO.Energiemenge em) - { + } - return em.Energieverbrauch.Select(v => v.Obiskennzahl).Distinct().Count() <= 1; + /// + /// test if Energiemenge has only one Obiskennzahl + /// + /// Energiemenge + /// true iff the Energiemenge->energieverbrauch list has at most one distinct Obiskennzahl + public static bool IsPureObisKennzahl(this BO.Energiemenge em) + { - } + return em.Energieverbrauch.Select(v => v.Obiskennzahl).Distinct().Count() <= 1; + + } - /// - /// test if all entries in do have same user properties. - /// Only tests for those user properties present. Missing user properties do not lead to false. - /// - /// Energiemenge - /// - public static bool IsPureUserProperties(this BO.Energiemenge em) - { - - ISet upKeys = new HashSet(em.Energieverbrauch.Where(v => v.UserProperties != null) - .SelectMany(v => v.UserProperties.Keys)); - var values = new Dictionary(); - // ToDo: make it nice. - foreach (var v in em.Energieverbrauch.Where(v => v.UserProperties != null)) - foreach (var key in upKeys) - if (v.UserProperties.TryGetValue(key, out var rawValue)) + /// + /// test if all entries in do have same user properties. + /// Only tests for those user properties present. Missing user properties do not lead to false. + /// + /// Energiemenge + /// + public static bool IsPureUserProperties(this BO.Energiemenge em) + { + + ISet upKeys = new HashSet(em.Energieverbrauch.Where(v => v.UserProperties != null) + .SelectMany(v => v.UserProperties.Keys)); + var values = new Dictionary(); + // ToDo: make it nice. + foreach (var v in em.Energieverbrauch.Where(v => v.UserProperties != null)) + foreach (var key in upKeys) + if (v.UserProperties.TryGetValue(key, out var rawValue)) + { + if (values.TryGetValue(key, out var onlyValue)) { - if (values.TryGetValue(key, out var onlyValue)) + if (rawValue == null && onlyValue != null) { - if (rawValue == null && onlyValue != null) - { - return false; - } - - if (rawValue != null && !rawValue.Equals(onlyValue)) - { - return false; - } + return false; } - else + + if (rawValue != null && !rawValue.Equals(onlyValue)) { - values.Add(key, rawValue); + return false; } } + else + { + values.Add(key, rawValue); + } + } - return true; + return true; - } + } + + /// + /// test if Energiemenge has only one + /// + /// Energiemenge + /// true iff the Energiemenge->energieverbrauch list does only contain entries with mutually convertible units + public static bool IsPureMengeneinheit(this BO.Energiemenge em) + { - /// - /// test if Energiemenge has only one - /// - /// Energiemenge - /// true iff the Energiemenge->energieverbrauch list does only contain entries with mutually convertible units - public static bool IsPureMengeneinheit(this BO.Energiemenge em) + if (em.Energieverbrauch.Select(v => v.Einheit).Distinct().Count() <= 1) { + return true; + } - if (em.Energieverbrauch.Select(v => v.Einheit).Distinct().Count() <= 1) - { - return true; - } + var me1 = em.Energieverbrauch.Select(v => v.Einheit).First(); + return em.Energieverbrauch.Select(v => v.Einheit).All(me2 => me1.IsConvertibleTo(me2)); - var me1 = em.Energieverbrauch.Select(v => v.Einheit).First(); - return em.Energieverbrauch.Select(v => v.Einheit).All(me2 => me1.IsConvertibleTo(me2)); + } - } + /// + /// opposite of + /// + /// Energiemenge + /// true iff all ->energieverbrauch entries are intensive + public static bool IsIntensive(this BO.Energiemenge em) + { + return !em.IsExtensive(); + } - /// - /// opposite of - /// - /// Energiemenge - /// true iff all ->energieverbrauch entries are intensive - public static bool IsIntensive(this BO.Energiemenge em) + /// + /// Test if the energiemenge contains only extensive consumption units + /// + /// Energiemenge + /// true iff all ->energieverbrauch entries are extensive + public static bool IsExtensive(this BO.Energiemenge em) + { + return em.IsPureMengeneinheit() && em.Energieverbrauch.First().Einheit.IsExtensive(); + } + + /// + /// Splits the energy menge in groups that share the same: + /// * , + /// * , + /// * + /// and are considered "pure". + /// + /// + /// a list of pure energiemengen () + public static List SplitInPureGroups(this BO.Energiemenge em) + { + if (em.Energieverbrauch == null) { - return !em.IsExtensive(); + return new List { em }; } - /// - /// Test if the energiemenge contains only extensive consumption units - /// - /// Energiemenge - /// true iff all ->energieverbrauch entries are extensive - public static bool IsExtensive(this BO.Energiemenge em) + var result = new List(); + foreach (var group in em.Energieverbrauch.GroupBy(PurityGrouper)) { - return em.IsPureMengeneinheit() && em.Energieverbrauch.First().Einheit.IsExtensive(); + var pureEm = em.DeepClone(); + pureEm.Energieverbrauch = group.ToList(); + result.Add(pureEm); } - /// - /// Splits the energy menge in groups that share the same: - /// * , - /// * , - /// * - /// and are considered "pure". - /// - /// - /// a list of pure energiemengen () - public static List SplitInPureGroups(this BO.Energiemenge em) - { - if (em.Energieverbrauch == null) - { - return new List { em }; - } - - var result = new List(); - foreach (var group in em.Energieverbrauch.GroupBy(PurityGrouper)) - { - var pureEm = em.DeepClone(); - pureEm.Energieverbrauch = group.ToList(); - result.Add(pureEm); - } - - return result; - } + return result; + } - /// - /// Apply to the . - /// - /// - public static void Detangle(this BO.Energiemenge em) + /// + /// Apply to the . + /// + /// + public static void Detangle(this BO.Energiemenge em) + { + if (em.Energieverbrauch != null) { - if (em.Energieverbrauch != null) - { - em.Energieverbrauch = VerbrauchExtension.Detangle(em.Energieverbrauch); - } + em.Energieverbrauch = VerbrauchExtension.Detangle(em.Energieverbrauch); } + } - private class BasicVerbrauchDateTimeComparer : IComparer + private class BasicVerbrauchDateTimeComparer : IComparer + { + int IComparer.Compare(CompletenessReport.BasicVerbrauch x, + CompletenessReport.BasicVerbrauch y) { - int IComparer.Compare(CompletenessReport.BasicVerbrauch x, - CompletenessReport.BasicVerbrauch y) + var vx = new Verbrauch { - var vx = new Verbrauch - { - Startdatum = x.Startdatum, - Enddatum = x.Enddatum - }; - var vy = new Verbrauch - { - Startdatum = y.Startdatum, - Enddatum = y.Enddatum - }; - IComparer cv = new VerbrauchDateTimeComparer(); - return cv.Compare(vx, vy); - } + Startdatum = x.Startdatum, + Enddatum = x.Enddatum + }; + var vy = new Verbrauch + { + Startdatum = y.Startdatum, + Enddatum = y.Enddatum + }; + IComparer cv = new VerbrauchDateTimeComparer(); + return cv.Compare(vx, vy); } } -} +} \ No newline at end of file diff --git a/BO4E.Extensions/BusinessObjects/Energiemenge/EnergiemengeExtensionCompleteness.cs b/BO4E.Extensions/BusinessObjects/Energiemenge/EnergiemengeExtensionCompleteness.cs index 95c5310d..ac83b47c 100644 --- a/BO4E.Extensions/BusinessObjects/Energiemenge/EnergiemengeExtensionCompleteness.cs +++ b/BO4E.Extensions/BusinessObjects/Energiemenge/EnergiemengeExtensionCompleteness.cs @@ -11,276 +11,275 @@ using System.Collections.Generic; using System.Linq; -namespace BO4E.Extensions.BusinessObjects.Energiemenge +namespace BO4E.Extensions.BusinessObjects.Energiemenge; + +public static partial class EnergiemengeExtension { - public static partial class EnergiemengeExtension + /// + /// Generate a for the given configuration. Same as + /// + /// but with all parameters in a configuration container instead of loose arguments. + /// + /// Energiemenge + /// configuration container + /// + public static CompletenessReport GetCompletenessReport(this BO.Energiemenge em, + CompletenessReport.CompletenessReportConfiguration config) { - /// - /// Generate a for the given configuration. Same as - /// - /// but with all parameters in a configuration container instead of loose arguments. - /// - /// Energiemenge - /// configuration container - /// - public static CompletenessReport GetCompletenessReport(this BO.Energiemenge em, - CompletenessReport.CompletenessReportConfiguration config) - { - return em.GetCompletenessReport( - new TimeRange(config.ReferenceTimeFrame.Startdatum.Value.UtcDateTime, - config.ReferenceTimeFrame.Enddatum.Value.UtcDateTime), config.Wertermittlungsverfahren, config.Obis, - config.Einheit); - } + return em.GetCompletenessReport( + new TimeRange(config.ReferenceTimeFrame.Startdatum.Value.UtcDateTime, + config.ReferenceTimeFrame.Enddatum.Value.UtcDateTime), config.Wertermittlungsverfahren, config.Obis, + config.Einheit); + } - /// - /// Generate a for the given refenrence time frame - /// - /// Energiemenge - /// reference time frame - /// - public static CompletenessReport GetCompletenessReport(this BO.Energiemenge em, ITimeRange reference) + /// + /// Generate a for the given refenrence time frame + /// + /// Energiemenge + /// reference time frame + /// + public static CompletenessReport GetCompletenessReport(this BO.Energiemenge em, ITimeRange reference) + { + var combis = em.GetWevObisMeCombinations(); + if (combis.Count != 1) { - var combis = em.GetWevObisMeCombinations(); - if (combis.Count != 1) + string errorMessage; + decimal? coverage; + if (combis.Count == 0) { - string errorMessage; - decimal? coverage; - if (combis.Count == 0) - { - errorMessage = "Cannot use autoconfigured method because there are no values."; - coverage = 0; - } - else - { - errorMessage = - $"Cannot use autoconfigured method because there are {combis.Count}>1 distinct (wertermittlungsverfahren, obis, einheit) tuple present: {JsonConvert.SerializeObject(combis, new StringEnumConverter())}"; - coverage = null; - } - - return new CompletenessReport - { - LokationsId = em.LokationsId, - ReferenceTimeFrame = new Zeitraum - { - Startdatum = new DateTimeOffset(reference.Start, TimeSpan.Zero), - Enddatum = new DateTimeOffset(reference.End, TimeSpan.Zero) - }, - Coverage = coverage, - ErrorMessage = errorMessage - }; + errorMessage = "Cannot use autoconfigured method because there are no values."; + coverage = 0; + } + else + { + errorMessage = + $"Cannot use autoconfigured method because there are {combis.Count}>1 distinct (wertermittlungsverfahren, obis, einheit) tuple present: {JsonConvert.SerializeObject(combis, new StringEnumConverter())}"; + coverage = null; } - var combi = combis.First(); - return em.GetCompletenessReport(reference, combi.Item1, combi.Item2, combi.Item3); - } - - /// - /// Generate a for the given parameters. - /// - /// Energiemenge - /// reference time frame - /// Wertermittlungsverfahren - /// OBIS Kennzahl - /// Mengeneinheit - /// the completeness report - public static CompletenessReport GetCompletenessReport(this BO.Energiemenge em, ITimeRange reference, - Wertermittlungsverfahren? wev, string obiskennzahl, Mengeneinheit einheit) - { - CompletenessReport result; - - result = new CompletenessReport + return new CompletenessReport { LokationsId = em.LokationsId, - Einheit = einheit, - Coverage = GetCoverage(em, reference, wev, obiskennzahl, einheit), - Wertermittlungsverfahren = wev, - Obiskennzahl = obiskennzahl, ReferenceTimeFrame = new Zeitraum { - Startdatum = new DateTimeOffset(DateTime.SpecifyKind(reference.Start, DateTimeKind.Utc)), - Enddatum = new DateTimeOffset(DateTime.SpecifyKind(reference.End, DateTimeKind.Utc)) - } + Startdatum = new DateTimeOffset(reference.Start, TimeSpan.Zero), + Enddatum = new DateTimeOffset(reference.End, TimeSpan.Zero) + }, + Coverage = coverage, + ErrorMessage = errorMessage }; + } + + var combi = combis.First(); + return em.GetCompletenessReport(reference, combi.Item1, combi.Item2, combi.Item3); + } + /// + /// Generate a for the given parameters. + /// + /// Energiemenge + /// reference time frame + /// Wertermittlungsverfahren + /// OBIS Kennzahl + /// Mengeneinheit + /// the completeness report + public static CompletenessReport GetCompletenessReport(this BO.Energiemenge em, ITimeRange reference, + Wertermittlungsverfahren? wev, string obiskennzahl, Mengeneinheit einheit) + { + CompletenessReport result; - if (em.Energieverbrauch != null && em.Energieverbrauch.Any()) + result = new CompletenessReport + { + LokationsId = em.LokationsId, + Einheit = einheit, + Coverage = GetCoverage(em, reference, wev, obiskennzahl, einheit), + Wertermittlungsverfahren = wev, + Obiskennzahl = obiskennzahl, + ReferenceTimeFrame = new Zeitraum { - /*using (MiniProfiler.Current.Step("populating time slices of/with missing/null values")) - { - result.values = em.GetMissingTimeRanges(reference, wev, obis, einheit) - .Select(mtr => new CompletenessReport.BasicVerbrauch - { - startdatum = DateTime.SpecifyKind(mtr.Start, DateTimeKind.Utc), - enddatum = DateTime.SpecifyKind(mtr.End, DateTimeKind.Utc), - wert = null - }).ToList(); - } - using (MiniProfiler.Current.Step("populating time slices existing values")) - { - result.values.AddRange( - em.energieverbrauch - //.AsParallel() - .Where(v => v.obiskennzahl == obis && v.einheit == einheit && v.wertermittlungsverfahren == wev) - .Select(v => new CompletenessReport.BasicVerbrauch - { - startdatum = DateTime.SpecifyKind(v.startdatum, DateTimeKind.Utc), - enddatum = DateTime.SpecifyKind(v.enddatum, DateTimeKind.Utc), - wert = v.wert - }) - .ToList()); - }*/ + Startdatum = new DateTimeOffset(DateTime.SpecifyKind(reference.Start, DateTimeKind.Utc)), + Enddatum = new DateTimeOffset(DateTime.SpecifyKind(reference.End, DateTimeKind.Utc)) + } + }; - var nonNullValues = - new TimePeriodCollection( - em.Energieverbrauch.Select(v => new TimeRange((v.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v.Enddatum ?? DateTimeOffset.MinValue).DateTime))); - ITimeRange limits; - if (result.ReferenceTimeFrame != null && result.ReferenceTimeFrame.Startdatum.HasValue) - { - limits = new TimeRange(result.ReferenceTimeFrame.Startdatum.Value.UtcDateTime, - result.ReferenceTimeFrame.Enddatum.Value.UtcDateTime); - } - else - { - limits = null; - } - var gaps = new TimeGapCalculator().GetGaps(nonNullValues, limits); - result.Gaps = gaps.Select(gap => new CompletenessReport.BasicVerbrauch + if (em.Energieverbrauch != null && em.Energieverbrauch.Any()) + { + /*using (MiniProfiler.Current.Step("populating time slices of/with missing/null values")) + { + result.values = em.GetMissingTimeRanges(reference, wev, obis, einheit) + .Select(mtr => new CompletenessReport.BasicVerbrauch + { + startdatum = DateTime.SpecifyKind(mtr.Start, DateTimeKind.Utc), + enddatum = DateTime.SpecifyKind(mtr.End, DateTimeKind.Utc), + wert = null + }).ToList(); + } + using (MiniProfiler.Current.Step("populating time slices existing values")) + { + result.values.AddRange( + em.energieverbrauch + //.AsParallel() + .Where(v => v.obiskennzahl == obis && v.einheit == einheit && v.wertermittlungsverfahren == wev) + .Select(v => new CompletenessReport.BasicVerbrauch { - Startdatum = DateTime.SpecifyKind(gap.Start, DateTimeKind.Utc), - Enddatum = DateTime.SpecifyKind(gap.End, DateTimeKind.Utc), - Wert = null - }).ToList(); + startdatum = DateTime.SpecifyKind(v.startdatum, DateTimeKind.Utc), + enddatum = DateTime.SpecifyKind(v.enddatum, DateTimeKind.Utc), + wert = v.wert + }) + .ToList()); + }*/ + var nonNullValues = + new TimePeriodCollection( + em.Energieverbrauch.Select(v => new TimeRange((v.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v.Enddatum ?? DateTimeOffset.MinValue).DateTime))); + ITimeRange limits; + if (result.ReferenceTimeFrame != null && result.ReferenceTimeFrame.Startdatum.HasValue) + { + limits = new TimeRange(result.ReferenceTimeFrame.Startdatum.Value.UtcDateTime, + result.ReferenceTimeFrame.Enddatum.Value.UtcDateTime); + } + else + { + limits = null; + } - /*using (MiniProfiler.Current.Step("sorting result")) - { - result.values.Sort(new BasicVerbrauchDateTimeComparer()); - }*/ - if (em.IsPure(true)) + var gaps = new TimeGapCalculator().GetGaps(nonNullValues, limits); + result.Gaps = gaps.Select(gap => new CompletenessReport.BasicVerbrauch + { + Startdatum = DateTime.SpecifyKind(gap.Start, DateTimeKind.Utc), + Enddatum = DateTime.SpecifyKind(gap.End, DateTimeKind.Utc), + Wert = null + }).ToList(); + + + /*using (MiniProfiler.Current.Step("sorting result")) + { + result.values.Sort(new BasicVerbrauchDateTimeComparer()); + }*/ + if (em.IsPure(true)) + { + try { - try + foreach (var kvp in em.Energieverbrauch.Where(v => v.UserProperties != null) + .SelectMany(v => v.UserProperties)) { - foreach (var kvp in em.Energieverbrauch.Where(v => v.UserProperties != null) - .SelectMany(v => v.UserProperties)) + if (result.UserProperties == null) { - if (result.UserProperties == null) - { - result.UserProperties = new Dictionary(); - } + result.UserProperties = new Dictionary(); + } - if (!result.UserProperties.ContainsKey(kvp.Key)) - { - result.UserProperties.Add(kvp.Key, kvp.Value); - } + if (!result.UserProperties.ContainsKey(kvp.Key)) + { + result.UserProperties.Add(kvp.Key, kvp.Value); } } - catch (InvalidOperationException) - { - // ok, there's no Verbrauch with user properties. - } + } + catch (InvalidOperationException) + { + // ok, there's no Verbrauch with user properties. } } + } - /*else - { - result.coverage = null; - result._errorMessage = "energieverbrauch is empty"; - }*/ - return result; + /*else + { + result.coverage = null; + result._errorMessage = "energieverbrauch is empty"; + }*/ + return result; + } + + /// + /// + /// for pure Energiemengen within their own time range. + /// + /// Energiemenge + /// + /// + /// + public static CompletenessReport GetCompletenessReport(this BO.Energiemenge em) + { + if (!em.IsPure()) + { + throw new ArgumentException( + "The provided Energiemenge is not pure. Please use overloaded method GetCompletenessReport(... , wertermittlungsverfahren, obiskennzahl, mengeneinheit)."); } - /// - /// - /// for pure Energiemengen within their own time range. - /// - /// Energiemenge - /// - /// - /// - public static CompletenessReport GetCompletenessReport(this BO.Energiemenge em) + Verbrauch v; + try { - if (!em.IsPure()) + v = em.Energieverbrauch.First(); + } + catch (InvalidOperationException) + { + return new CompletenessReport { - throw new ArgumentException( - "The provided Energiemenge is not pure. Please use overloaded method GetCompletenessReport(... , wertermittlungsverfahren, obiskennzahl, mengeneinheit)."); - } + Coverage = null, + LokationsId = em.LokationsId, + ErrorMessage = "energieverbrauch is empty" + }; + } - Verbrauch v; - try - { - v = em.Energieverbrauch.First(); - } - catch (InvalidOperationException) - { - return new CompletenessReport - { - Coverage = null, - LokationsId = em.LokationsId, - ErrorMessage = "energieverbrauch is empty" - }; - } + return em.GetCompletenessReport(em.GetTimeRange(), v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit); + } - return em.GetCompletenessReport(em.GetTimeRange(), v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit); + /// + /// creates a dictionary of completeness reports for a given list of reference time ranges. + /// + /// Energiemenge + /// list of ranges for which the completeness reports are generated + /// set true to internally use parallel linq + /// + public static IDictionary GetSlicedCompletenessReports(this BO.Energiemenge em, + IEnumerable ranges, bool useParallelExecution = false) + { + if (ranges == null) + { + throw new ArgumentNullException(nameof(ranges), "list of time ranges must not be null"); } - /// - /// creates a dictionary of completeness reports for a given list of reference time ranges. - /// - /// Energiemenge - /// list of ranges for which the completeness reports are generated - /// set true to internally use parallel linq - /// - public static IDictionary GetSlicedCompletenessReports(this BO.Energiemenge em, - IEnumerable ranges, bool useParallelExecution = false) + if (ranges.Any()) { - if (ranges == null) + if (useParallelExecution) { - throw new ArgumentNullException(nameof(ranges), "list of time ranges must not be null"); + return ranges.AsParallel().ToDictionary(r => r, r => GetCompletenessReport(em, r)); } - if (ranges.Any()) - { - if (useParallelExecution) - { - return ranges.AsParallel().ToDictionary(r => r, r => GetCompletenessReport(em, r)); - } - - return ranges.ToDictionary(r => r, r => GetCompletenessReport(em, r)); - } - - return new Dictionary(); + return ranges.ToDictionary(r => r, r => GetCompletenessReport(em, r)); } - /// - /// Get Daily Completeness Reports for . The magic is, that it takes DST into - /// account! - /// - /// Energiemenge - /// overall time frame. Beginning and end must have same hour/minute/second - /// set true to internally use parallel linq - /// - public static IDictionary GetDailyCompletenessReports(this BO.Energiemenge em, - ITimeRange overallTimeRange, bool useParallelExecution = false) - { - var slices = GetLocalDailySlices(overallTimeRange); - return em.GetSlicedCompletenessReports(slices, useParallelExecution); - } + return new Dictionary(); + } - /// - /// Get Monthly Completeness Reports for . - /// - /// Energiemenge - /// - /// set true to internally use parallel linq - /// - public static IDictionary GetMonthlyCompletenessReports(this BO.Energiemenge em, - ITimeRange overallTimeRange, bool useParallelExecution = false) - { - var slices = GetLocalMonthlySlices(overallTimeRange); - return em.GetSlicedCompletenessReports(slices, useParallelExecution); - } + /// + /// Get Daily Completeness Reports for . The magic is, that it takes DST into + /// account! + /// + /// Energiemenge + /// overall time frame. Beginning and end must have same hour/minute/second + /// set true to internally use parallel linq + /// + public static IDictionary GetDailyCompletenessReports(this BO.Energiemenge em, + ITimeRange overallTimeRange, bool useParallelExecution = false) + { + var slices = GetLocalDailySlices(overallTimeRange); + return em.GetSlicedCompletenessReports(slices, useParallelExecution); + } + + /// + /// Get Monthly Completeness Reports for . + /// + /// Energiemenge + /// + /// set true to internally use parallel linq + /// + public static IDictionary GetMonthlyCompletenessReports(this BO.Energiemenge em, + ITimeRange overallTimeRange, bool useParallelExecution = false) + { + var slices = GetLocalMonthlySlices(overallTimeRange); + return em.GetSlicedCompletenessReports(slices, useParallelExecution); } } \ No newline at end of file diff --git a/BO4E.Extensions/BusinessObjects/Energiemenge/EnergiemengeExtensionPlausibility.cs b/BO4E.Extensions/BusinessObjects/Energiemenge/EnergiemengeExtensionPlausibility.cs index de575bc6..9279c0cd 100644 --- a/BO4E.Extensions/BusinessObjects/Energiemenge/EnergiemengeExtensionPlausibility.cs +++ b/BO4E.Extensions/BusinessObjects/Energiemenge/EnergiemengeExtensionPlausibility.cs @@ -13,232 +13,231 @@ using static BO4E.Extensions.ENUM.MengeneinheitExtenion; using static BO4E.Reporting.PlausibilityReport; -namespace BO4E.Extensions.BusinessObjects.Energiemenge +namespace BO4E.Extensions.BusinessObjects.Energiemenge; + +public static partial class EnergiemengeExtension { - public static partial class EnergiemengeExtension + /// + /// Returns a that compares with + /// . + /// within the interval defined in . + /// + /// reference Energiemenge (reference = used for normalisation) + /// other Energiemenge + /// + /// time frame to be analysed. If null, the overlap of and + /// is used. + /// + /// + /// By default (false) an ArgumentException is thrown if the + /// do not match. Setting this flag suppresses the error. + /// + /// a + public static PlausibilityReport GetPlausibilityReport(this BO.Energiemenge emReference, + BO.Energiemenge emOther, ITimeRange timeframe = null, bool ignoreLocation = false) { - /// - /// Returns a that compares with - /// . - /// within the interval defined in . - /// - /// reference Energiemenge (reference = used for normalisation) - /// other Energiemenge - /// - /// time frame to be analysed. If null, the overlap of and - /// is used. - /// - /// - /// By default (false) an ArgumentException is thrown if the - /// do not match. Setting this flag suppresses the error. - /// - /// a - public static PlausibilityReport GetPlausibilityReport(this BO.Energiemenge emReference, - BO.Energiemenge emOther, ITimeRange timeframe = null, bool ignoreLocation = false) - { - var trReference = emReference.GetTimeRange(); - var trOther = emOther.GetTimeRange(); - if (timeframe == null) - { - var overlap = trReference.GetIntersection(trOther); - if (!ignoreLocation) - { - if (!(emReference.LokationsId == emOther.LokationsId && - emReference.LokationsTyp == emOther.LokationsTyp)) - { - throw new ArgumentException( - $"locations do not match! '{emReference.LokationsId}' ({emReference.LokationsTyp}) != '{emOther.LokationsId}' ({emOther.LokationsTyp})"); - } - } - - timeframe = overlap; - } - - Tuple consumptionReference; - Tuple consumptionOtherRaw; - consumptionReference = emReference.GetConsumption(timeframe); - consumptionOtherRaw = emOther.GetConsumption(timeframe); - - Tuple consumptionOther; - if (consumptionReference.Item2 != consumptionOtherRaw.Item2) + var trReference = emReference.GetTimeRange(); + var trOther = emOther.GetTimeRange(); + if (timeframe == null) + { + var overlap = trReference.GetIntersection(trOther); + if (!ignoreLocation) { - // unit mismatch - if (consumptionReference.Item2.IsConvertibleTo(consumptionOtherRaw.Item2)) - { - consumptionOther = new Tuple( - consumptionOtherRaw.Item1 * - consumptionOtherRaw.Item2.GetConversionFactor(consumptionReference.Item2), - consumptionReference.Item2); - } - else + if (!(emReference.LokationsId == emOther.LokationsId && + emReference.LokationsTyp == emOther.LokationsTyp)) { throw new ArgumentException( - $"The unit {consumptionOtherRaw.Item2} is not comparable to {consumptionReference.Item2}!"); + $"locations do not match! '{emReference.LokationsId}' ({emReference.LokationsTyp}) != '{emOther.LokationsId}' ({emOther.LokationsTyp})"); } } - else - { - consumptionOther = consumptionOtherRaw; - } - var absoluteDeviation = consumptionOther.Item1 - consumptionReference.Item1; - decimal? relativeDeviation; - try - { - relativeDeviation = absoluteDeviation / consumptionReference.Item1; - } - catch (DivideByZeroException) - { - relativeDeviation = null; - } + timeframe = overlap; + } - var vReference = - emReference.Energieverbrauch.FirstOrDefault(); // copies obiskennzahl, wertermittlungsverfahren... - vReference.Wert = consumptionReference.Item1; - vReference.Einheit = consumptionReference.Item2; - vReference.Startdatum = timeframe.Start; - vReference.Enddatum = timeframe.End; - - var vOther = - emOther.Energieverbrauch.FirstOrDefault(); // copies obiskennzahl, wertermittlungsverfahren... - vOther.Wert = consumptionOther.Item1; - vOther.Einheit = consumptionOther.Item2; - vOther.Startdatum = timeframe.Start; - vOther.Enddatum = timeframe.End; - - var pr = new PlausibilityReport - { - LokationsId = emReference.LokationsId, - ReferenceTimeFrame = new Zeitraum - { - Startdatum = new DateTimeOffset(timeframe.Start), - Enddatum = new DateTimeOffset(timeframe.End) - }, - VerbrauchReference = vReference, - VerbrauchOther = vOther, - AbsoluteDeviation = Math.Abs(absoluteDeviation), - AbsoluteDeviationEinheit = consumptionReference.Item2 - }; - if (relativeDeviation.HasValue) + Tuple consumptionReference; + Tuple consumptionOtherRaw; + consumptionReference = emReference.GetConsumption(timeframe); + consumptionOtherRaw = emOther.GetConsumption(timeframe); + + Tuple consumptionOther; + if (consumptionReference.Item2 != consumptionOtherRaw.Item2) + { + // unit mismatch + if (consumptionReference.Item2.IsConvertibleTo(consumptionOtherRaw.Item2)) { - pr.RelativeDeviation = Math.Round(relativeDeviation.Value, 4); + consumptionOther = new Tuple( + consumptionOtherRaw.Item1 * + consumptionOtherRaw.Item2.GetConversionFactor(consumptionReference.Item2), + consumptionReference.Item2); } else { - pr.RelativeDeviation = null; + throw new ArgumentException( + $"The unit {consumptionOtherRaw.Item2} is not comparable to {consumptionReference.Item2}!"); } + } + else + { + consumptionOther = consumptionOtherRaw; + } - return pr; - + var absoluteDeviation = consumptionOther.Item1 - consumptionReference.Item1; + decimal? relativeDeviation; + try + { + relativeDeviation = absoluteDeviation / consumptionReference.Item1; + } + catch (DivideByZeroException) + { + relativeDeviation = null; } - /// - /// same as - /// - /// but with a strongly typed container as input. - /// - /// container containing the relevant data - /// - /// - public static PlausibilityReport GetPlausibilityReport(this BO.Energiemenge energiemenge, - PlausibilityReportConfiguration config) - { - return energiemenge.GetPlausibilityReport(config.Other, - new TimeRange(config.Timeframe.Startdatum.Value.UtcDateTime, - config.Timeframe.Enddatum.Value.UtcDateTime), config.IgnoreLocation); + var vReference = + emReference.Energieverbrauch.FirstOrDefault(); // copies obiskennzahl, wertermittlungsverfahren... + vReference.Wert = consumptionReference.Item1; + vReference.Einheit = consumptionReference.Item2; + vReference.Startdatum = timeframe.Start; + vReference.Enddatum = timeframe.End; + + var vOther = + emOther.Energieverbrauch.FirstOrDefault(); // copies obiskennzahl, wertermittlungsverfahren... + vOther.Wert = consumptionOther.Item1; + vOther.Einheit = consumptionOther.Item2; + vOther.Startdatum = timeframe.Start; + vOther.Enddatum = timeframe.End; + + var pr = new PlausibilityReport + { + LokationsId = emReference.LokationsId, + ReferenceTimeFrame = new Zeitraum + { + Startdatum = new DateTimeOffset(timeframe.Start), + Enddatum = new DateTimeOffset(timeframe.End) + }, + VerbrauchReference = vReference, + VerbrauchOther = vOther, + AbsoluteDeviation = Math.Abs(absoluteDeviation), + AbsoluteDeviationEinheit = consumptionReference.Item2 + }; + if (relativeDeviation.HasValue) + { + pr.RelativeDeviation = Math.Round(relativeDeviation.Value, 4); + } + else + { + pr.RelativeDeviation = null; } - /// - /// creates a dictionary of completeness reports for a given list of reference time ranges. - /// - /// Energiemenge - /// container containing the relevant data - /// list of ranges for which the completeness reports are generated - /// - public static IDictionary GetSlicedPlausibilityReports(this BO.Energiemenge em, - PlausibilityReportConfiguration config, IEnumerable ranges) - { - if (ranges == null) - { - throw new ArgumentNullException(nameof(ranges), "list of time ranges must not be null"); - } + return pr; - var result = new Dictionary(); - foreach (var range in ranges) - { - var localConfig = - JsonConvert.DeserializeObject(JsonConvert.SerializeObject(config)); - localConfig.Timeframe = new Zeitraum - { - Startdatum = range.Start, - Enddatum = range.End - }; - var subResult = GetPlausibilityReport(em, localConfig); - result.Add(range, subResult); - } + } - return result; + /// + /// same as + /// + /// but with a strongly typed container as input. + /// + /// container containing the relevant data + /// + /// + public static PlausibilityReport GetPlausibilityReport(this BO.Energiemenge energiemenge, + PlausibilityReportConfiguration config) + { + return energiemenge.GetPlausibilityReport(config.Other, + new TimeRange(config.Timeframe.Startdatum.Value.UtcDateTime, + config.Timeframe.Enddatum.Value.UtcDateTime), config.IgnoreLocation); + } + + /// + /// creates a dictionary of completeness reports for a given list of reference time ranges. + /// + /// Energiemenge + /// container containing the relevant data + /// list of ranges for which the completeness reports are generated + /// + public static IDictionary GetSlicedPlausibilityReports(this BO.Energiemenge em, + PlausibilityReportConfiguration config, IEnumerable ranges) + { + if (ranges == null) + { + throw new ArgumentNullException(nameof(ranges), "list of time ranges must not be null"); } - /// - /// Get Daily Completeness Reports for overall time range defined in . - /// The magic is, that it takes DST into account! - /// - /// Energiemenge - /// - /// configuration that contains the overall time range in - /// - /// - /// - public static IDictionary GetDailyPlausibilityReports(this BO.Energiemenge em, - PlausibilityReportConfiguration config) - { - if (config == null) + var result = new Dictionary(); + foreach (var range in ranges) + { + var localConfig = + JsonConvert.DeserializeObject(JsonConvert.SerializeObject(config)); + localConfig.Timeframe = new Zeitraum { - throw new ArgumentNullException(nameof(config)); - } + Startdatum = range.Start, + Enddatum = range.End + }; + var subResult = GetPlausibilityReport(em, localConfig); + result.Add(range, subResult); + } - if (config.Timeframe == null) - { - throw new ArgumentNullException(nameof(config.Timeframe)); - } + return result; + } - var slices = GetLocalDailySlices(new TimeRange - { - Start = config.Timeframe.Startdatum.Value.UtcDateTime, - End = config.Timeframe.Enddatum.Value.UtcDateTime - }); - return em.GetSlicedPlausibilityReports(config, slices); + /// + /// Get Daily Completeness Reports for overall time range defined in . + /// The magic is, that it takes DST into account! + /// + /// Energiemenge + /// + /// configuration that contains the overall time range in + /// + /// + /// + public static IDictionary GetDailyPlausibilityReports(this BO.Energiemenge em, + PlausibilityReportConfiguration config) + { + if (config == null) + { + throw new ArgumentNullException(nameof(config)); } - /// - /// Get Monthly Completeness Reports for overall time range defined in . - /// - /// Energiemenge - /// - /// configuration that contains the overall time range in - /// - /// - /// - public static IDictionary GetMonthlyPlausibilityReports(this BO.Energiemenge em, - PlausibilityReportConfiguration config) - { - if (config == null) - { - throw new ArgumentNullException(nameof(config)); - } + if (config.Timeframe == null) + { + throw new ArgumentNullException(nameof(config.Timeframe)); + } - if (config.Timeframe == null) - { - throw new ArgumentNullException(nameof(config.Timeframe)); - } + var slices = GetLocalDailySlices(new TimeRange + { + Start = config.Timeframe.Startdatum.Value.UtcDateTime, + End = config.Timeframe.Enddatum.Value.UtcDateTime + }); + return em.GetSlicedPlausibilityReports(config, slices); + } - var slices = GetLocalMonthlySlices(new TimeRange - { - Start = config.Timeframe.Startdatum.Value.UtcDateTime, - End = config.Timeframe.Enddatum.Value.UtcDateTime - }); - return em.GetSlicedPlausibilityReports(config, slices); + /// + /// Get Monthly Completeness Reports for overall time range defined in . + /// + /// Energiemenge + /// + /// configuration that contains the overall time range in + /// + /// + /// + public static IDictionary GetMonthlyPlausibilityReports(this BO.Energiemenge em, + PlausibilityReportConfiguration config) + { + if (config == null) + { + throw new ArgumentNullException(nameof(config)); } + + if (config.Timeframe == null) + { + throw new ArgumentNullException(nameof(config.Timeframe)); + } + + var slices = GetLocalMonthlySlices(new TimeRange + { + Start = config.Timeframe.Startdatum.Value.UtcDateTime, + End = config.Timeframe.Enddatum.Value.UtcDateTime + }); + return em.GetSlicedPlausibilityReports(config, slices); } } \ No newline at end of file diff --git a/BO4E.Extensions/BusinessObjects/Energiemenge/EnergiemengeExtensionSlicingHelper.cs b/BO4E.Extensions/BusinessObjects/Energiemenge/EnergiemengeExtensionSlicingHelper.cs index 9128389f..60b936d9 100644 --- a/BO4E.Extensions/BusinessObjects/Energiemenge/EnergiemengeExtensionSlicingHelper.cs +++ b/BO4E.Extensions/BusinessObjects/Energiemenge/EnergiemengeExtensionSlicingHelper.cs @@ -4,189 +4,188 @@ using BO4E.meta; using Itenso.TimePeriod; -namespace BO4E.Extensions.BusinessObjects.Energiemenge +namespace BO4E.Extensions.BusinessObjects.Energiemenge; + +/// Do calculations on top of an Energiemenge BO4E. +public static partial class EnergiemengeExtension { - /// Do calculations on top of an Energiemenge BO4E. - public static partial class EnergiemengeExtension + internal static IList GetLocalDailySlices(ITimeRange overallTimeRange, TimeZoneInfo tz = null) { - internal static IList GetLocalDailySlices(ITimeRange overallTimeRange, TimeZoneInfo tz = null) + if (overallTimeRange == null) { - if (overallTimeRange == null) - { - throw new ArgumentNullException(nameof(overallTimeRange), "overall time range must not be null"); - } + throw new ArgumentNullException(nameof(overallTimeRange), "overall time range must not be null"); + } - if (tz == null) - { - tz = CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo; - } + if (tz == null) + { + tz = CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo; + } - if (overallTimeRange.Start.Kind == DateTimeKind.Unspecified) - { - throw new ArgumentException("TimeRange start must not have DateTimeKind.Unspecified", - nameof(overallTimeRange)); - } + if (overallTimeRange.Start.Kind == DateTimeKind.Unspecified) + { + throw new ArgumentException("TimeRange start must not have DateTimeKind.Unspecified", + nameof(overallTimeRange)); + } - if (overallTimeRange.End.Kind == DateTimeKind.Unspecified) - { - throw new ArgumentException("TimeRange end must not have DateTimeKind.Unspecified", - nameof(overallTimeRange)); - } + if (overallTimeRange.End.Kind == DateTimeKind.Unspecified) + { + throw new ArgumentException("TimeRange end must not have DateTimeKind.Unspecified", + nameof(overallTimeRange)); + } - IList result = new List(); - if (!overallTimeRange.IsMoment) + IList result = new List(); + if (!overallTimeRange.IsMoment) + { + result.Add(new TimeRange { + Start = overallTimeRange.Start, + End = overallTimeRange.Start.AddDaysDST(1) + }); + while (result.Last().End < overallTimeRange.End) result.Add(new TimeRange { - Start = overallTimeRange.Start, - End = overallTimeRange.Start.AddDaysDST(1) + Start = result.Last().Start.AddDaysDST(1), + End = result.Last().End.AddDaysDST(1) }); - while (result.Last().End < overallTimeRange.End) - result.Add(new TimeRange - { - Start = result.Last().Start.AddDaysDST(1), - End = result.Last().End.AddDaysDST(1) - }); - } + } - return result; + return result; + } + + internal static IList GetLocalMonthlySlices(ITimeRange overallTimeRange, TimeZoneInfo tz = null) + { + if (overallTimeRange == null) + { + throw new ArgumentNullException(nameof(overallTimeRange), "overall time range must not be null"); } - internal static IList GetLocalMonthlySlices(ITimeRange overallTimeRange, TimeZoneInfo tz = null) + DateTime localStart; + DateTime localEnd; + if (tz == null) { - if (overallTimeRange == null) + tz = CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo; + + if (overallTimeRange.Start.Kind != DateTimeKind.Utc) { - throw new ArgumentNullException(nameof(overallTimeRange), "overall time range must not be null"); + throw new ArgumentException( + $"TimeRange start must have DateTimeKind.Utc if no timezone is given in parameter {nameof(tz)}", + nameof(overallTimeRange)); } - DateTime localStart; - DateTime localEnd; - if (tz == null) + if (overallTimeRange.End.Kind != DateTimeKind.Utc) { - tz = CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo; - - if (overallTimeRange.Start.Kind != DateTimeKind.Utc) - { - throw new ArgumentException( - $"TimeRange start must have DateTimeKind.Utc if no timezone is given in parameter {nameof(tz)}", - nameof(overallTimeRange)); - } + throw new ArgumentException( + $"TimeRange end must have DateTimeKind.Utc if no timezone is given in parameter {nameof(tz)}", + nameof(overallTimeRange)); + } - if (overallTimeRange.End.Kind != DateTimeKind.Utc) - { - throw new ArgumentException( - $"TimeRange end must have DateTimeKind.Utc if no timezone is given in parameter {nameof(tz)}", + localStart = TimeZoneInfo.ConvertTimeFromUtc(overallTimeRange.Start, tz); + localEnd = TimeZoneInfo.ConvertTimeFromUtc(overallTimeRange.End, tz); + } + else + { + switch (overallTimeRange.Start.Kind) + { + case DateTimeKind.Local: + throw new ArgumentException($"{nameof(DateTimeKind.Local)} not allowed for Start", nameof(overallTimeRange)); - } - - localStart = TimeZoneInfo.ConvertTimeFromUtc(overallTimeRange.Start, tz); - localEnd = TimeZoneInfo.ConvertTimeFromUtc(overallTimeRange.End, tz); + case DateTimeKind.Unspecified: + localStart = overallTimeRange.Start; + break; + case DateTimeKind.Utc: + localStart = TimeZoneInfo.ConvertTimeFromUtc(overallTimeRange.Start, tz); + break; + default: + throw new NotImplementedException(); } - else + + switch (overallTimeRange.End.Kind) { - switch (overallTimeRange.Start.Kind) - { - case DateTimeKind.Local: - throw new ArgumentException($"{nameof(DateTimeKind.Local)} not allowed for Start", - nameof(overallTimeRange)); - case DateTimeKind.Unspecified: - localStart = overallTimeRange.Start; - break; - case DateTimeKind.Utc: - localStart = TimeZoneInfo.ConvertTimeFromUtc(overallTimeRange.Start, tz); - break; - default: - throw new NotImplementedException(); - } + case DateTimeKind.Local: + throw new ArgumentException($"{nameof(DateTimeKind.Local)} not allowed for End", + nameof(overallTimeRange)); + case DateTimeKind.Unspecified: + localEnd = overallTimeRange.End; + break; + case DateTimeKind.Utc: + localEnd = TimeZoneInfo.ConvertTimeFromUtc(overallTimeRange.End, tz); + break; - switch (overallTimeRange.End.Kind) - { - case DateTimeKind.Local: - throw new ArgumentException($"{nameof(DateTimeKind.Local)} not allowed for End", - nameof(overallTimeRange)); - case DateTimeKind.Unspecified: - localEnd = overallTimeRange.End; - break; - case DateTimeKind.Utc: - localEnd = TimeZoneInfo.ConvertTimeFromUtc(overallTimeRange.End, tz); - break; - - default: - throw new NotImplementedException(); - } + default: + throw new NotImplementedException(); } + } - localStart = DateTime.SpecifyKind(localStart, DateTimeKind.Unspecified); - localEnd = DateTime.SpecifyKind(localEnd, DateTimeKind.Unspecified); - IList result = new List(); - if (!overallTimeRange.IsMoment) + localStart = DateTime.SpecifyKind(localStart, DateTimeKind.Unspecified); + localEnd = DateTime.SpecifyKind(localEnd, DateTimeKind.Unspecified); + IList result = new List(); + if (!overallTimeRange.IsMoment) + { + var initialStart = + new DateTime(localStart.Year, localStart.Month, 1, 0, 0, 0, DateTimeKind.Unspecified); + var initialEnd = initialStart.AddMonths(1); + result.Add(new TimeRange { - var initialStart = - new DateTime(localStart.Year, localStart.Month, 1, 0, 0, 0, DateTimeKind.Unspecified); - var initialEnd = initialStart.AddMonths(1); + Start = initialStart, + End = initialEnd + }); + while (result.Last().End < overallTimeRange.End) + { + var sliceStart = result.Last().Start.AddMonths(1); result.Add(new TimeRange { - Start = initialStart, - End = initialEnd + Start = sliceStart, + End = sliceStart.AddMonths(1) }); - while (result.Last().End < overallTimeRange.End) - { - var sliceStart = result.Last().Start.AddMonths(1); - result.Add(new TimeRange - { - Start = sliceStart, - End = sliceStart.AddMonths(1) - }); - } } - - return result - .Select(tr => (ITimeRange)new TimeRange - { - Start = TimeZoneInfo.ConvertTimeToUtc(tr.Start, tz), - End = TimeZoneInfo.ConvertTimeToUtc(tr.End, tz) - }) - .Where(tr => tr.Start >= overallTimeRange.Start && tr.End <= overallTimeRange.End) - .ToList(); } - /// - /// adds days to . Adding 1 day might actually add 25 or 23 hours if - /// the transisition DST<->non-DST happens. - /// - /// datetime (kind unspecified or Utc) - /// number of days to add - /// - /// timezone is meant to be iff dt.Kind == DateTimeKind.Unspecified, default (if - /// null) is - /// - /// - public static DateTime AddDaysDST(this DateTime dt, double value, TimeZoneInfo tz = null) - { - if (tz == null) + return result + .Select(tr => (ITimeRange)new TimeRange { - tz = CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo; - } + Start = TimeZoneInfo.ConvertTimeToUtc(tr.Start, tz), + End = TimeZoneInfo.ConvertTimeToUtc(tr.End, tz) + }) + .Where(tr => tr.Start >= overallTimeRange.Start && tr.End <= overallTimeRange.End) + .ToList(); + } - switch (dt.Kind) - { - case DateTimeKind.Local: - throw new ArgumentException("DateTime Kind must not be local", nameof(dt)); - case DateTimeKind.Unspecified: - return - dt.AddDays(value); // doesn't take dst into account. that's just what we want! A day can have 23,24 or 25 hours - case DateTimeKind.Utc: - { - // an utc day does always have 24 hours. not what humans expect! - var dtLocal = DateTime.SpecifyKind(TimeZoneInfo.ConvertTimeFromUtc(dt, tz), - DateTimeKind.Unspecified); - var preResult = DateTime.SpecifyKind(dtLocal.AddDays(value), DateTimeKind.Unspecified); - var result = TimeZoneInfo.ConvertTimeToUtc(preResult, tz); - return result; - } - default: - throw new NotImplementedException($"DateTimeKind {dt.Kind} is not implemented."); - } + /// + /// adds days to . Adding 1 day might actually add 25 or 23 hours if + /// the transisition DST<->non-DST happens. + /// + /// datetime (kind unspecified or Utc) + /// number of days to add + /// + /// timezone is meant to be iff dt.Kind == DateTimeKind.Unspecified, default (if + /// null) is + /// + /// + public static DateTime AddDaysDST(this DateTime dt, double value, TimeZoneInfo tz = null) + { + if (tz == null) + { + tz = CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo; + } + + switch (dt.Kind) + { + case DateTimeKind.Local: + throw new ArgumentException("DateTime Kind must not be local", nameof(dt)); + case DateTimeKind.Unspecified: + return + dt.AddDays(value); // doesn't take dst into account. that's just what we want! A day can have 23,24 or 25 hours + case DateTimeKind.Utc: + { + // an utc day does always have 24 hours. not what humans expect! + var dtLocal = DateTime.SpecifyKind(TimeZoneInfo.ConvertTimeFromUtc(dt, tz), + DateTimeKind.Unspecified); + var preResult = DateTime.SpecifyKind(dtLocal.AddDays(value), DateTimeKind.Unspecified); + var result = TimeZoneInfo.ConvertTimeToUtc(preResult, tz); + return result; + } + default: + throw new NotImplementedException($"DateTimeKind {dt.Kind} is not implemented."); } } } \ No newline at end of file diff --git a/BO4E.Extensions/COM/COM.cs b/BO4E.Extensions/COM/COM.cs index 531781ce..e30da90f 100644 --- a/BO4E.Extensions/COM/COM.cs +++ b/BO4E.Extensions/COM/COM.cs @@ -1,21 +1,20 @@ using Newtonsoft.Json; -namespace BO4E.Extensions.COM +namespace BO4E.Extensions.COM; + +/// +/// common extensions for all COM objects +/// +public static class COMExtensions { /// - /// common extensions for all COM objects + /// Create a deep copy of a COMponent /// - public static class COMExtensions + /// Type of the COM + /// the BO that is copied + /// the deep copy + public static T DeepClone(this T source) where T : BO4E.COM.COM { - /// - /// Create a deep copy of a COMponent - /// - /// Type of the COM - /// the BO that is copied - /// the deep copy - public static T DeepClone(this T source) where T : BO4E.COM.COM - { - return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(source)); - } + return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(source)); } } \ No newline at end of file diff --git a/BO4E.Extensions/COM/PhysikalischerWertExtension.cs b/BO4E.Extensions/COM/PhysikalischerWertExtension.cs index 01e6d917..bd9d3e9b 100644 --- a/BO4E.Extensions/COM/PhysikalischerWertExtension.cs +++ b/BO4E.Extensions/COM/PhysikalischerWertExtension.cs @@ -2,24 +2,23 @@ using BO4E.ENUM; using BO4E.Extensions.ENUM; -namespace BO4E.Extensions.COM +namespace BO4E.Extensions.COM; + +/// +/// extensions for +/// +public static class PhysikalischerWertExtension { /// - /// extensions for + /// Converts a PhysikalischerWert to another unit, e.g. from kWh to MWh. This changes the + /// and the accordingly /// - public static class PhysikalischerWertExtension + /// physikalischer Wert + /// new unit of measurement + /// a new instance of PhysikalischerWert having the unit + public static PhysikalischerWert ConvertToUnit(this PhysikalischerWert pw, Mengeneinheit newEinheit) { - /// - /// Converts a PhysikalischerWert to another unit, e.g. from kWh to MWh. This changes the - /// and the accordingly - /// - /// physikalischer Wert - /// new unit of measurement - /// a new instance of PhysikalischerWert having the unit - public static PhysikalischerWert ConvertToUnit(this PhysikalischerWert pw, Mengeneinheit newEinheit) - { - var factor = pw.Einheit.GetConversionFactor(newEinheit); // throws all the exceptions. - return new PhysikalischerWert(factor * pw.Wert, newEinheit); - } + var factor = pw.Einheit.GetConversionFactor(newEinheit); // throws all the exceptions. + return new PhysikalischerWert(factor * pw.Wert, newEinheit); } } \ No newline at end of file diff --git a/BO4E.Extensions/COM/VerbrauchExtension.cs b/BO4E.Extensions/COM/VerbrauchExtension.cs index 9100e8c8..4f341563 100644 --- a/BO4E.Extensions/COM/VerbrauchExtension.cs +++ b/BO4E.Extensions/COM/VerbrauchExtension.cs @@ -7,191 +7,184 @@ using Itenso.TimePeriod; using Newtonsoft.Json; -namespace BO4E.Extensions.COM +namespace BO4E.Extensions.COM; + +/// +/// Extension Methods for +/// +public static class VerbrauchExtension { /// - /// Extension Methods for + /// Merging two Verbrauch instances means adding their values whenever it's possible. + /// But generally the result is going to contain multiple Verbrauchs. /// - public static class VerbrauchExtension - { - /// - /// Merging two Verbrauch instances means adding their values whenever it's possible. - /// But generally the result is going to contain multiple Verbrauchs. - /// - /// - /// - /// - public static HashSet Merge(this Verbrauch v1, Verbrauch v2) => - v1.Merge(v2, false, false); + /// + /// + /// + public static HashSet Merge(this Verbrauch v1, Verbrauch v2) => + v1.Merge(v2, false, false); - /// - /// Apply to the provided Verbräuche. - /// But remove identical entries that occur in both and - /// - /// - /// - /// - /// - public static HashSet MergeRedundant(this Verbrauch v1, Verbrauch v2, bool biased) => - v1.Merge(v2, true, biased); + /// + /// Apply to the provided Verbräuche. + /// But remove identical entries that occur in both and + /// + /// + /// + /// + /// + public static HashSet MergeRedundant(this Verbrauch v1, Verbrauch v2, bool biased) => + v1.Merge(v2, true, biased); - /// - /// merge two entities. - /// Merging means that two entites are moved into one entites that has the same properties as the two combined. - /// Depending on the unit this could mean adding their values or averaging them. - /// See the unittests for details. - /// - /// - /// - /// - /// - /// - /// - public static HashSet Merge(this Verbrauch v1, Verbrauch v2, bool redundant, bool biased) + /// + /// merge two entities. + /// Merging means that two entites are moved into one entites that has the same properties as the two combined. + /// Depending on the unit this could mean adding their values or averaging them. + /// See the unittests for details. + /// + /// + /// + /// + /// + /// + /// + public static HashSet Merge(this Verbrauch v1, Verbrauch v2, bool redundant, bool biased) + { + var result = new HashSet(); + if (v1.Obiskennzahl == v2.Obiskennzahl && v1.Wertermittlungsverfahren == v2.Wertermittlungsverfahren && + v1.Einheit == v2.Einheit) { - var result = new HashSet(); - if (v1.Obiskennzahl == v2.Obiskennzahl && v1.Wertermittlungsverfahren == v2.Wertermittlungsverfahren && - v1.Einheit == v2.Einheit) + if (v1.OverlapsWith(v2)) { - if (v1.OverlapsWith(v2)) + // don't wanna deal with time running backwards. + //Debug.Assert(v1.enddatum >= v1.startdatum); + //Debug.Assert(v2.enddatum >= v2.startdatum); + var tr1 = new TimeRange((v1.Startdatum ?? DateTimeOffset.MinValue).UtcDateTime, (v1.Enddatum ?? DateTimeOffset.MinValue).UtcDateTime); + var tr2 = new TimeRange((v2.Startdatum ?? DateTimeOffset.MinValue).UtcDateTime, (v2.Enddatum ?? DateTimeOffset.MinValue).UtcDateTime); + var overlap = v1.GetIntersection(v2); + if (v1.Einheit.IsExtensive()) { - // don't wanna deal with time running backwards. - //Debug.Assert(v1.enddatum >= v1.startdatum); - //Debug.Assert(v2.enddatum >= v2.startdatum); - var tr1 = new TimeRange((v1.Startdatum ?? DateTimeOffset.MinValue).UtcDateTime, (v1.Enddatum ?? DateTimeOffset.MinValue).UtcDateTime); - var tr2 = new TimeRange((v2.Startdatum ?? DateTimeOffset.MinValue).UtcDateTime, (v2.Enddatum ?? DateTimeOffset.MinValue).UtcDateTime); - var overlap = v1.GetIntersection(v2); - if (v1.Einheit.IsExtensive()) + var vmerge = new Verbrauch { - var vmerge = new Verbrauch - { - Obiskennzahl = v1.Obiskennzahl, - Einheit = v1.Einheit, - Wertermittlungsverfahren = v1.Wertermittlungsverfahren - }; - if (redundant) + Obiskennzahl = v1.Obiskennzahl, + Einheit = v1.Einheit, + Wertermittlungsverfahren = v1.Wertermittlungsverfahren + }; + if (redundant) + { + var exclusiveV1Wert = + (decimal)(tr1.Duration.TotalSeconds - overlap.Duration.TotalSeconds) * v1.Wert / + (decimal)tr1.Duration.TotalSeconds; + var exclusiveV2Wert = + (decimal)(tr2.Duration.TotalSeconds - overlap.Duration.TotalSeconds) * v2.Wert / + (decimal)tr2.Duration.TotalSeconds; + var overlapV1Wert = (decimal)overlap.Duration.TotalSeconds * v1.Wert / + (decimal)tr1.Duration.TotalSeconds; + var overlapV2Wert = (decimal)overlap.Duration.TotalSeconds * v2.Wert / + (decimal)tr2.Duration.TotalSeconds; + if (biased) { - var exclusiveV1Wert = - (decimal)(tr1.Duration.TotalSeconds - overlap.Duration.TotalSeconds) * v1.Wert / - (decimal)tr1.Duration.TotalSeconds; - var exclusiveV2Wert = - (decimal)(tr2.Duration.TotalSeconds - overlap.Duration.TotalSeconds) * v2.Wert / - (decimal)tr2.Duration.TotalSeconds; - var overlapV1Wert = (decimal)overlap.Duration.TotalSeconds * v1.Wert / - (decimal)tr1.Duration.TotalSeconds; - var overlapV2Wert = (decimal)overlap.Duration.TotalSeconds * v2.Wert / - (decimal)tr2.Duration.TotalSeconds; - if (biased) + // biased ==> assume that v2 is contained in v1 + vmerge.Startdatum = v1.Startdatum; + vmerge.Enddatum = v1.Enddatum; + if (exclusiveV1Wert == 0.0M && exclusiveV2Wert == 0.0M && + overlapV1Wert == overlapV2Wert) { - // biased ==> assume that v2 is contained in v1 - vmerge.Startdatum = v1.Startdatum; - vmerge.Enddatum = v1.Enddatum; - if (exclusiveV1Wert == 0.0M && exclusiveV2Wert == 0.0M && - overlapV1Wert == overlapV2Wert) - { - vmerge.Wert = overlapV1Wert; - } - else - { - vmerge.Wert = v1.Wert - overlapV2Wert; // overlapV1Wert; - } + vmerge.Wert = overlapV1Wert; } else { - vmerge.Startdatum = v1.Startdatum; - vmerge.Enddatum = v2.Startdatum; - vmerge.Wert = v1.Wert - overlapV2Wert; + vmerge.Wert = v1.Wert - overlapV2Wert; // overlapV1Wert; } } else { - vmerge.Startdatum = v1.Startdatum < v2.Startdatum ? v1.Startdatum : v2.Startdatum; - vmerge.Enddatum = v1.Enddatum > v2.Enddatum ? v1.Enddatum : v2.Enddatum; - vmerge.Wert = v1.Wert + v2.Wert; + vmerge.Startdatum = v1.Startdatum; + vmerge.Enddatum = v2.Startdatum; + vmerge.Wert = v1.Wert - overlapV2Wert; } - - result.Add(vmerge); } else { - var vmerge1 = new Verbrauch - { - Obiskennzahl = v1.Obiskennzahl, - Einheit = v1.Einheit, - Wertermittlungsverfahren = v1.Wertermittlungsverfahren, - Startdatum = v1.Startdatum < v2.Startdatum ? v1.Startdatum : v2.Startdatum, - Enddatum = new DateTimeOffset(overlap.Start, TimeSpan.Zero), - Wert = v1.Startdatum < v2.Startdatum ? v1.Wert : v2.Wert - }; - var vmerge2 = new Verbrauch - { - Obiskennzahl = v1.Obiskennzahl, - Einheit = v1.Einheit, - Wertermittlungsverfahren = v1.Wertermittlungsverfahren, - Startdatum = new DateTimeOffset(overlap.Start, TimeSpan.Zero), - Enddatum = new DateTimeOffset(overlap.End, TimeSpan.Zero), - }; - if (redundant) - { - if (v1.Wert != v2.Wert) - { - throw new ArgumentException( - $"Data cannot be redundant if values ({v1.Wert}{v1.Einheit} vs. {v2.Wert}{v2.Einheit}) don't match for interval [{vmerge2.Startdatum}, {vmerge2.Enddatum})."); - } - - vmerge2.Wert = v1.Wert; - } - else - { - vmerge2.Wert = v1.Wert + v2.Wert; - } - - var vmerge3 = new Verbrauch - { - Obiskennzahl = v1.Obiskennzahl, - Einheit = v1.Einheit, - Wertermittlungsverfahren = v1.Wertermittlungsverfahren, - Startdatum = overlap.End, - Enddatum = v1.Enddatum > v2.Enddatum ? v1.Enddatum : v2.Enddatum, - Wert = v1.Enddatum > v2.Enddatum ? v1.Wert : v2.Wert - }; - result.Add(vmerge1); - result.Add(vmerge2); - result.Add(vmerge3); + vmerge.Startdatum = v1.Startdatum < v2.Startdatum ? v1.Startdatum : v2.Startdatum; + vmerge.Enddatum = v1.Enddatum > v2.Enddatum ? v1.Enddatum : v2.Enddatum; + vmerge.Wert = v1.Wert + v2.Wert; } + + result.Add(vmerge); } - else if (v1.Startdatum == v2.Enddatum || v2.Startdatum == v1.Enddatum) + else { - var start = v1.Startdatum < v2.Startdatum ? v1.Startdatum : v2.Startdatum; - var stop = v1.Enddatum > v2.Enddatum ? v1.Enddatum : v2.Enddatum; - var vmerge = new Verbrauch + var vmerge1 = new Verbrauch { Obiskennzahl = v1.Obiskennzahl, Einheit = v1.Einheit, Wertermittlungsverfahren = v1.Wertermittlungsverfahren, - Startdatum = start, - Enddatum = stop + Startdatum = v1.Startdatum < v2.Startdatum ? v1.Startdatum : v2.Startdatum, + Enddatum = new DateTimeOffset(overlap.Start, TimeSpan.Zero), + Wert = v1.Startdatum < v2.Startdatum ? v1.Wert : v2.Wert }; - if (v1.Einheit.IsExtensive()) + var vmerge2 = new Verbrauch { - vmerge.Wert = v1.Wert + v2.Wert; - result.Add(vmerge); - } - else if (v1.Wert == v2.Wert) // implicitly intensive + Obiskennzahl = v1.Obiskennzahl, + Einheit = v1.Einheit, + Wertermittlungsverfahren = v1.Wertermittlungsverfahren, + Startdatum = new DateTimeOffset(overlap.Start, TimeSpan.Zero), + Enddatum = new DateTimeOffset(overlap.End, TimeSpan.Zero), + }; + if (redundant) { - vmerge.Wert = v1.Wert; - result.Add(vmerge); + if (v1.Wert != v2.Wert) + { + throw new ArgumentException( + $"Data cannot be redundant if values ({v1.Wert}{v1.Einheit} vs. {v2.Wert}{v2.Einheit}) don't match for interval [{vmerge2.Startdatum}, {vmerge2.Enddatum})."); + } + + vmerge2.Wert = v1.Wert; } else { - // merging intensive verbrauch with different values is not possible. - result.Add(v1); - result.Add(v2); + vmerge2.Wert = v1.Wert + v2.Wert; } + + var vmerge3 = new Verbrauch + { + Obiskennzahl = v1.Obiskennzahl, + Einheit = v1.Einheit, + Wertermittlungsverfahren = v1.Wertermittlungsverfahren, + Startdatum = overlap.End, + Enddatum = v1.Enddatum > v2.Enddatum ? v1.Enddatum : v2.Enddatum, + Wert = v1.Enddatum > v2.Enddatum ? v1.Wert : v2.Wert + }; + result.Add(vmerge1); + result.Add(vmerge2); + result.Add(vmerge3); + } + } + else if (v1.Startdatum == v2.Enddatum || v2.Startdatum == v1.Enddatum) + { + var start = v1.Startdatum < v2.Startdatum ? v1.Startdatum : v2.Startdatum; + var stop = v1.Enddatum > v2.Enddatum ? v1.Enddatum : v2.Enddatum; + var vmerge = new Verbrauch + { + Obiskennzahl = v1.Obiskennzahl, + Einheit = v1.Einheit, + Wertermittlungsverfahren = v1.Wertermittlungsverfahren, + Startdatum = start, + Enddatum = stop + }; + if (v1.Einheit.IsExtensive()) + { + vmerge.Wert = v1.Wert + v2.Wert; + result.Add(vmerge); + } + else if (v1.Wert == v2.Wert) // implicitly intensive + { + vmerge.Wert = v1.Wert; + result.Add(vmerge); } else { - // laaaangweilig ;) + // merging intensive verbrauch with different values is not possible. result.Add(v1); result.Add(v2); } @@ -202,232 +195,238 @@ public static HashSet Merge(this Verbrauch v1, Verbrauch v2, bool red result.Add(v1); result.Add(v2); } - - result.RemoveWhere(v => - v.Einheit.IsIntensive() && new TimeRange((v.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v.Enddatum ?? DateTimeOffset.MinValue).DateTime).Duration.TotalMilliseconds == 0); - return result; } - - /// - /// returns time range from , - /// - /// Verbrauch - /// - public static TimeRange GetTimeRange(this Verbrauch v) + else { - return new TimeRange((v.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v.Enddatum ?? DateTimeOffset.MinValue).DateTime); + // laaaangweilig ;) + result.Add(v1); + result.Add(v2); } - /// - /// - /// - /// - /// - public static TimeSpan GetDuration(this Verbrauch v) => v.GetTimeRange().Duration; + result.RemoveWhere(v => + v.Einheit.IsIntensive() && new TimeRange((v.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v.Enddatum ?? DateTimeOffset.MinValue).DateTime).Duration.TotalMilliseconds == 0); + return result; + } + /// + /// returns time range from , + /// + /// Verbrauch + /// + public static TimeRange GetTimeRange(this Verbrauch v) + { + return new TimeRange((v.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v.Enddatum ?? DateTimeOffset.MinValue).DateTime); + } + + /// + /// + /// + /// + /// + public static TimeSpan GetDuration(this Verbrauch v) => v.GetTimeRange().Duration; - /// - /// De-tangles a list of overlapping Verbrauch entries where entries can be subsets of other entries. - /// - /// - /// [---v1---) - /// [-----v2------) - /// [---------v3---------) - /// is transformed into - /// [--v1---) - /// ........[-v2--) - /// ..............[--v3--) - /// - /// - /// - public static List Detangle(IEnumerable input) + + /// + /// De-tangles a list of overlapping Verbrauch entries where entries can be subsets of other entries. + /// + /// + /// [---v1---) + /// [-----v2------) + /// [---------v3---------) + /// is transformed into + /// [--v1---) + /// ........[-v2--) + /// ..............[--v3--) + /// + /// + /// + public static List Detangle(IEnumerable input) + { + //var filteredInput = KeepShortestSlices(input); + var resultSet = new HashSet(); + var groups = input.OrderBy(v => (v.Startdatum, v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit)) + .GroupBy(v => new Tuple + ( + v.Wertermittlungsverfahren, + v.Obiskennzahl, + v.Einheit + )); + foreach (var vGroup in groups) { - //var filteredInput = KeepShortestSlices(input); - var resultSet = new HashSet(); - var groups = input.OrderBy(v => (v.Startdatum, v.Wertermittlungsverfahren, v.Obiskennzahl, v.Einheit)) - .GroupBy(v => new Tuple - ( - v.Wertermittlungsverfahren, - v.Obiskennzahl, - v.Einheit - )); - foreach (var vGroup in groups) + var subResult = new HashSet(); + + // find pairs (x,y) where x.end == y.start: + // |----x----|--------y--------| + //var adjacentVerbrauchs = from x in vGroup join y in vGroup on x.enddatum equals y.startdatum select new { x, y }; + var adjacentVerbrauchs = + from x in vGroup join y in vGroup on x.Enddatum equals y.Startdatum select new { x, y }; + foreach (var av in adjacentVerbrauchs) { - var subResult = new HashSet(); + subResult.Add(av.x); + subResult.Add(av.y); + } - // find pairs (x,y) where x.end == y.start: - // |----x----|--------y--------| - //var adjacentVerbrauchs = from x in vGroup join y in vGroup on x.enddatum equals y.startdatum select new { x, y }; - var adjacentVerbrauchs = - from x in vGroup join y in vGroup on x.Enddatum equals y.Startdatum select new { x, y }; - foreach (var av in adjacentVerbrauchs) + // |----x----|--------y--------| + // |-------------z-------------| + // ==> delete z from result where z.start == x.start and z.end == y.end + //var fullyRedundantVerbrauchs = from av in adjacentVerbrauchs join z in vGroup on new { av.x.startdatum, av.y.enddatum } equals new { z.startdatum, z.enddatum } select new { av, z }; + var fullyRedundantVerbrauchs = from av in adjacentVerbrauchs + join z in vGroup on new { av.x.Startdatum, av.y.Enddatum } equals new { z.Startdatum, z.Enddatum } + select new { av, z }; + foreach (var frv in fullyRedundantVerbrauchs) + { + if (frv.av.x.Wert + frv.av.y.Wert != frv.z.Wert) { - subResult.Add(av.x); - subResult.Add(av.y); + throw new ArgumentException( + $"Inconsistent data detected: {JsonConvert.SerializeObject(frv.av.x)} + {JsonConvert.SerializeObject(frv.av.y)} ≠ {JsonConvert.SerializeObject(frv.z)}"); } - // |----x----|--------y--------| - // |-------------z-------------| - // ==> delete z from result where z.start == x.start and z.end == y.end - //var fullyRedundantVerbrauchs = from av in adjacentVerbrauchs join z in vGroup on new { av.x.startdatum, av.y.enddatum } equals new { z.startdatum, z.enddatum } select new { av, z }; - var fullyRedundantVerbrauchs = from av in adjacentVerbrauchs - join z in vGroup on new { av.x.Startdatum, av.y.Enddatum } equals new { z.Startdatum, z.Enddatum } - select new { av, z }; - foreach (var frv in fullyRedundantVerbrauchs) - { - if (frv.av.x.Wert + frv.av.y.Wert != frv.z.Wert) - { - throw new ArgumentException( - $"Inconsistent data detected: {JsonConvert.SerializeObject(frv.av.x)} + {JsonConvert.SerializeObject(frv.av.y)} ≠ {JsonConvert.SerializeObject(frv.z)}"); - } - - subResult.Remove(frv.z); - } + subResult.Remove(frv.z); + } - // |----------x----------|---y---| - // |---------------z-------------| - // or - // |---y---|----------x----------| - // |---------------z-------------| - // or - // |---x1--|-----y------|---x2---| - // |--------------z--------------| - // y and z are given. find x such that x.value == y.value+z.value - //subResult.UnionWith(vGroup); - subResult.UnionWith(vGroup); - foreach (var z in new HashSet(subResult)) + // |----------x----------|---y---| + // |---------------z-------------| + // or + // |---y---|----------x----------| + // |---------------z-------------| + // or + // |---x1--|-----y------|---x2---| + // |--------------z--------------| + // y and z are given. find x such that x.value == y.value+z.value + //subResult.UnionWith(vGroup); + subResult.UnionWith(vGroup); + foreach (var z in new HashSet(subResult)) + { + var ys = subResult.Where(y => z.Contains(y) && !z.Equals(y)); + if (ys.Any()) { - var ys = subResult.Where(y => z.Contains(y) && !z.Equals(y)); - if (ys.Any()) + var tps = new TimePeriodSubtractor(); + var source = new TimePeriodCollection { z.GetTimeRange() }; + var subtract = new TimePeriodCollection(); + subtract.AddAll(ys.Select(y => y.GetTimeRange())); + var subtractionResult = tps.SubtractPeriods(source, subtract); + var xs = new HashSet(); + foreach (var tr in subtractionResult) { - var tps = new TimePeriodSubtractor(); - var source = new TimePeriodCollection { z.GetTimeRange() }; - var subtract = new TimePeriodCollection(); - subtract.AddAll(ys.Select(y => y.GetTimeRange())); - var subtractionResult = tps.SubtractPeriods(source, subtract); - var xs = new HashSet(); - foreach (var tr in subtractionResult) + var v = new Verbrauch { - var v = new Verbrauch - { - Einheit = z.Einheit, - Wertermittlungsverfahren = z.Wertermittlungsverfahren, - Obiskennzahl = z.Obiskennzahl, - Startdatum = new DateTimeOffset(tr.Start, TimeSpan.Zero), - Enddatum = new DateTimeOffset(tr.End, TimeSpan.Zero) - }; - xs.Add(v); - } - - var totalXWert = z.Wert - ys.Select(y => y.Wert).Sum(); - var totalXDuration = xs.Select(x => x.GetDuration().TotalSeconds).Sum(); - foreach (var x in xs) - x.Wert = totalXWert * (decimal)x.GetDuration().TotalSeconds / (decimal)totalXDuration; - subResult.Remove(z); - subResult.UnionWith(xs); + Einheit = z.Einheit, + Wertermittlungsverfahren = z.Wertermittlungsverfahren, + Obiskennzahl = z.Obiskennzahl, + Startdatum = new DateTimeOffset(tr.Start, TimeSpan.Zero), + Enddatum = new DateTimeOffset(tr.End, TimeSpan.Zero) + }; + xs.Add(v); } - } - resultSet.UnionWith(subResult); + var totalXWert = z.Wert - ys.Select(y => y.Wert).Sum(); + var totalXDuration = xs.Select(x => x.GetDuration().TotalSeconds).Sum(); + foreach (var x in xs) + x.Wert = totalXWert * (decimal)x.GetDuration().TotalSeconds / (decimal)totalXDuration; + subResult.Remove(z); + subResult.UnionWith(xs); + } } - var result = new List(resultSet); - result.Sort(new VerbrauchDateTimeComparer()); - return result; + resultSet.UnionWith(subResult); } - /// - /// convert to another unit if possible - /// - /// Verbrauch - /// Mengeneinheit - /// ArgumentException if units are not convertible - public static void ConvertToUnit(this Verbrauch v, Mengeneinheit mengeneinheit) - { - var oldWert = new PhysikalischerWert(v.Wert, v.Einheit); - var newWert = oldWert.ConvertToUnit(mengeneinheit); - v.Wert = newWert.Wert; - v.Einheit = newWert.Einheit; - } + var result = new List(resultSet); + result.Sort(new VerbrauchDateTimeComparer()); + return result; + } - /// - /// Test if the time ranges [startdatum, enddatum) overlap. - /// - /// - /// - /// - /// true iff [.startdatum, .enddatum) and [ - /// .startdatum, .enddatum) overlap - /// - public static bool OverlapsWith(this Verbrauch v1, Verbrauch v2) - { - return v1.OverlapsWith(new TimeRange((v2.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v2.Enddatum ?? DateTimeOffset.MinValue).DateTime, true)); - } + /// + /// convert to another unit if possible + /// + /// Verbrauch + /// Mengeneinheit + /// ArgumentException if units are not convertible + public static void ConvertToUnit(this Verbrauch v, Mengeneinheit mengeneinheit) + { + var oldWert = new PhysikalischerWert(v.Wert, v.Einheit); + var newWert = oldWert.ConvertToUnit(mengeneinheit); + v.Wert = newWert.Wert; + v.Einheit = newWert.Einheit; + } - /// - /// - /// - /// - /// - /// - public static bool OverlapsWith(this Verbrauch v1, ITimeRange tr2) - { - return new TimeRange((v1.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v1.Enddatum ?? DateTimeOffset.MinValue).DateTime).OverlapsWith(tr2); - } + /// + /// Test if the time ranges [startdatum, enddatum) overlap. + /// + /// + /// + /// + /// true iff [.startdatum, .enddatum) and [ + /// .startdatum, .enddatum) overlap + /// + public static bool OverlapsWith(this Verbrauch v1, Verbrauch v2) + { + return v1.OverlapsWith(new TimeRange((v2.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v2.Enddatum ?? DateTimeOffset.MinValue).DateTime, true)); + } - /// - /// - /// - /// - /// - /// - public static ITimeRange GetIntersection(this Verbrauch v1, ITimeRange tr2) - { - return new TimeRange((v1.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v1.Enddatum ?? DateTimeOffset.MinValue).DateTime).GetIntersection(tr2); - } + /// + /// + /// + /// + /// + /// + public static bool OverlapsWith(this Verbrauch v1, ITimeRange tr2) + { + return new TimeRange((v1.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v1.Enddatum ?? DateTimeOffset.MinValue).DateTime).OverlapsWith(tr2); + } - /// - /// - /// - /// - /// - /// - public static ITimeRange GetIntersection(this Verbrauch v1, Verbrauch v2) - { - return v1.GetIntersection(new TimeRange((v2.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v2.Enddatum ?? DateTimeOffset.MinValue).DateTime)); - } + /// + /// + /// + /// + /// + /// + public static ITimeRange GetIntersection(this Verbrauch v1, ITimeRange tr2) + { + return new TimeRange((v1.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v1.Enddatum ?? DateTimeOffset.MinValue).DateTime).GetIntersection(tr2); + } - /// - /// - /// - /// - /// - /// - public static bool Contains(this Verbrauch v1, Verbrauch v2) - { - return v1.OverlapsWith(v2) && v1.Startdatum <= v2.Startdatum && v1.Enddatum >= v2.Enddatum; - } + /// + /// + /// + /// + /// + /// + public static ITimeRange GetIntersection(this Verbrauch v1, Verbrauch v2) + { + return v1.GetIntersection(new TimeRange((v2.Startdatum ?? DateTimeOffset.MinValue).DateTime, (v2.Enddatum ?? DateTimeOffset.MinValue).DateTime)); + } - /// - /// Allows to sort lists of by , - /// ascending - /// - public class VerbrauchDateTimeComparer : IComparer + /// + /// + /// + /// + /// + /// + public static bool Contains(this Verbrauch v1, Verbrauch v2) + { + return v1.OverlapsWith(v2) && v1.Startdatum <= v2.Startdatum && v1.Enddatum >= v2.Enddatum; + } + + /// + /// Allows to sort lists of by , + /// ascending + /// + public class VerbrauchDateTimeComparer : IComparer + { + int IComparer.Compare(Verbrauch x, Verbrauch y) { - int IComparer.Compare(Verbrauch x, Verbrauch y) + if (x.Startdatum != y.Startdatum) { - if (x.Startdatum != y.Startdatum) - { - return DateTimeOffset.Compare(x.Startdatum ?? DateTimeOffset.MinValue, y.Startdatum ?? DateTimeOffset.MinValue); - } - - if (x.Enddatum != y.Enddatum) - { - return DateTimeOffset.Compare(x.Enddatum ?? DateTimeOffset.MinValue, y.Enddatum ?? DateTimeOffset.MinValue); - } + return DateTimeOffset.Compare(x.Startdatum ?? DateTimeOffset.MinValue, y.Startdatum ?? DateTimeOffset.MinValue); + } - return 0; + if (x.Enddatum != y.Enddatum) + { + return DateTimeOffset.Compare(x.Enddatum ?? DateTimeOffset.MinValue, y.Enddatum ?? DateTimeOffset.MinValue); } + + return 0; } } } \ No newline at end of file diff --git a/BO4E.Extensions/COM/ZeitraumExtension.cs b/BO4E.Extensions/COM/ZeitraumExtension.cs index 7be1a497..c9562d1f 100644 --- a/BO4E.Extensions/COM/ZeitraumExtension.cs +++ b/BO4E.Extensions/COM/ZeitraumExtension.cs @@ -1,19 +1,18 @@ -namespace BO4E.Extensions.COM +namespace BO4E.Extensions.COM; + +/// +/// Extension methods for +/// +public static class ZeitraumExtension { - /// - /// Extension methods for - /// - public static class ZeitraumExtension + /* + public static implicit operator Zeitraum(TimeRange tr) { - /* - public static implicit operator Zeitraum(TimeRange tr) + return new Zeitraum { - return new Zeitraum - { - startdatum = tr.Start, - enddatum = tr.End - }; - } - */ + startdatum = tr.Start, + enddatum = tr.End + }; } + */ } \ No newline at end of file diff --git a/BO4E.Extensions/ENUM/MengeneinheitExtension.cs b/BO4E.Extensions/ENUM/MengeneinheitExtension.cs index e620ba97..4f5a034a 100644 --- a/BO4E.Extensions/ENUM/MengeneinheitExtension.cs +++ b/BO4E.Extensions/ENUM/MengeneinheitExtension.cs @@ -3,136 +3,135 @@ using System.Linq; using BO4E.ENUM; -namespace BO4E.Extensions.ENUM +namespace BO4E.Extensions.ENUM; + +/// +/// Extension Methods for Mengeneinheit. +/// +public static class MengeneinheitExtenion { /// - /// Extension Methods for Mengeneinheit. + /// This set contains sets of Mengeneinheiten that share the same dimension (e.g. time, power, work, volume) + /// Einheiten in the same subset are considered convertible amongst each other. + /// + public static readonly ISet> DimensionSets = new HashSet> + { + new HashSet {Mengeneinheit.WH, Mengeneinheit.KWH, Mengeneinheit.MWH}, + new HashSet {Mengeneinheit.KW, Mengeneinheit.MW}, + new HashSet + {Mengeneinheit.JAHR, Mengeneinheit.MONAT, Mengeneinheit.TAG, Mengeneinheit.STUNDE}, + new HashSet {Mengeneinheit.ANZAHL}, + new HashSet {Mengeneinheit.KUBIKMETER}, + new HashSet {Mengeneinheit.VAR, Mengeneinheit.KVAR}, + new HashSet {Mengeneinheit.VARH, Mengeneinheit.KVARH}, + new HashSet {Mengeneinheit.KWHK} + }; + + /// + /// Tests if two Mengeneinheit are convertible into each other / do have the same kind. /// - public static class MengeneinheitExtenion + /// + /// + /// true iff convertible + public static bool AreConvertible(Mengeneinheit me1, Mengeneinheit me2) { - /// - /// This set contains sets of Mengeneinheiten that share the same dimension (e.g. time, power, work, volume) - /// Einheiten in the same subset are considered convertible amongst each other. - /// - public static readonly ISet> DimensionSets = new HashSet> +#pragma warning disable 618 + if (me1 == Mengeneinheit.ZERO || me2 == Mengeneinheit.ZERO) { - new HashSet {Mengeneinheit.WH, Mengeneinheit.KWH, Mengeneinheit.MWH}, - new HashSet {Mengeneinheit.KW, Mengeneinheit.MW}, - new HashSet - {Mengeneinheit.JAHR, Mengeneinheit.MONAT, Mengeneinheit.TAG, Mengeneinheit.STUNDE}, - new HashSet {Mengeneinheit.ANZAHL}, - new HashSet {Mengeneinheit.KUBIKMETER}, - new HashSet {Mengeneinheit.VAR, Mengeneinheit.KVAR}, - new HashSet {Mengeneinheit.VARH, Mengeneinheit.KVARH}, - new HashSet {Mengeneinheit.KWHK} - }; + return false; + } +#pragma warning restore 618 + return DimensionSets.Any(einheitengroup => einheitengroup.Contains(me1) && einheitengroup.Contains(me2)); + } + + /// + /// Similar to AreConvertible but as extension method for me1 + /// + /// + /// + /// + public static bool IsConvertibleTo(this Mengeneinheit me1, Mengeneinheit me2) + { + return AreConvertible(me1, me2); + } + + /// + /// Is the Mengeneinheit intensive? + /// + /// + /// true iff not extensive + public static bool IsIntensive(this Mengeneinheit me) + { + return !IsExtensive(me); + } - /// - /// Tests if two Mengeneinheit are convertible into each other / do have the same kind. - /// - /// - /// - /// true iff convertible - public static bool AreConvertible(Mengeneinheit me1, Mengeneinheit me2) + /// + /// is the Mengeneinheit extensive? + /// + /// + /// true iff extensive + public static bool IsExtensive(this Mengeneinheit me) + { + switch (me) { -#pragma warning disable 618 - if (me1 == Mengeneinheit.ZERO || me2 == Mengeneinheit.ZERO) - { + case Mengeneinheit.ANZAHL: + return true; + case Mengeneinheit.JAHR: + return true; + case Mengeneinheit.KUBIKMETER: + return true; + case Mengeneinheit.KW: + return false; + case Mengeneinheit.KWH: + return true; + case Mengeneinheit.MONAT: + return true; + case Mengeneinheit.MWH: + return true; + case Mengeneinheit.STUNDE: + return true; + case Mengeneinheit.TAG: + return true; + case Mengeneinheit.WH: + return true; + default: return false; - } -#pragma warning restore 618 - return DimensionSets.Any(einheitengroup => einheitengroup.Contains(me1) && einheitengroup.Contains(me2)); } + } - /// - /// Similar to AreConvertible but as extension method for me1 - /// - /// - /// - /// - public static bool IsConvertibleTo(this Mengeneinheit me1, Mengeneinheit me2) + /// + /// returns the factor that is needed to convert an amount in unit to an equivalent amount in + /// unit . + /// + /// source unit + /// target unit + /// + /// iff units do not have the same dimension + public static decimal GetConversionFactor(this Mengeneinheit me1, Mengeneinheit me2) + { +#pragma warning disable 618 + if (me1 == Mengeneinheit.ZERO || me2 == Mengeneinheit.ZERO) +#pragma warning restore 618 { - return AreConvertible(me1, me2); + throw new InvalidOperationException("You must not use the artificial 'ZERO' value."); } - /// - /// Is the Mengeneinheit intensive? - /// - /// - /// true iff not extensive - public static bool IsIntensive(this Mengeneinheit me) + if (me1 == me2) { - return !IsExtensive(me); + return 1.0M; } - /// - /// is the Mengeneinheit extensive? - /// - /// - /// true iff extensive - public static bool IsExtensive(this Mengeneinheit me) + if (!me1.IsConvertibleTo(me2)) { - switch (me) - { - case Mengeneinheit.ANZAHL: - return true; - case Mengeneinheit.JAHR: - return true; - case Mengeneinheit.KUBIKMETER: - return true; - case Mengeneinheit.KW: - return false; - case Mengeneinheit.KWH: - return true; - case Mengeneinheit.MONAT: - return true; - case Mengeneinheit.MWH: - return true; - case Mengeneinheit.STUNDE: - return true; - case Mengeneinheit.TAG: - return true; - case Mengeneinheit.WH: - return true; - default: - return false; - } + throw new InvalidOperationException( + $"{me1} and {me2} are not convertible into each other because they don't share the same dimension."); } - /// - /// returns the factor that is needed to convert an amount in unit to an equivalent amount in - /// unit . - /// - /// source unit - /// target unit - /// - /// iff units do not have the same dimension - public static decimal GetConversionFactor(this Mengeneinheit me1, Mengeneinheit me2) + if ((int)me1 % (int)me2 == 0 || (int)me2 % (int)me2 == 0) { -#pragma warning disable 618 - if (me1 == Mengeneinheit.ZERO || me2 == Mengeneinheit.ZERO) -#pragma warning restore 618 - { - throw new InvalidOperationException("You must not use the artificial 'ZERO' value."); - } - - if (me1 == me2) - { - return 1.0M; - } - - if (!me1.IsConvertibleTo(me2)) - { - throw new InvalidOperationException( - $"{me1} and {me2} are not convertible into each other because they don't share the same dimension."); - } - - if ((int)me1 % (int)me2 == 0 || (int)me2 % (int)me2 == 0) - { - return (decimal)me1 / (decimal)me2; - } - - throw new InvalidOperationException($"{me1} and {me2} are not (trivially) convertible into each other."); + return (decimal)me1 / (decimal)me2; } + + throw new InvalidOperationException($"{me1} and {me2} are not (trivially) convertible into each other."); } } \ No newline at end of file diff --git a/BO4E.Reporting/CompletenessReport.cs b/BO4E.Reporting/CompletenessReport.cs index 1fd1ec7a..c6eed5cb 100644 --- a/BO4E.Reporting/CompletenessReport.cs +++ b/BO4E.Reporting/CompletenessReport.cs @@ -10,320 +10,319 @@ using BO4E.meta; using Newtonsoft.Json; -namespace BO4E.Reporting +namespace BO4E.Reporting; + +/// +/// A completeness report contains information about the completeness of a pure +/// . In this context "pure" means, that the Energiemenge +/// does only contain one distinct set of (, , +/// ). +/// +public class CompletenessReport : Report, IComparable { /// - /// A completeness report contains information about the completeness of a pure - /// . In this context "pure" means, that the Energiemenge - /// does only contain one distinct set of (, , - /// ). + /// matches a OBIS-Kennzahl that stands for an intelligentes messsystem for power. /// - public class CompletenessReport : Report, IComparable - { - /// - /// matches a OBIS-Kennzahl that stands for an intelligentes messsystem for power. - /// - private static readonly Regex imsysRegex = new Regex(@"(1)-(65):((?:[1-8]|99))\.((?:6|8|9|29))\.([0-9]{1,2})", - RegexOptions.Compiled); + private static readonly Regex imsysRegex = new Regex(@"(1)-(65):((?:[1-8]|99))\.((?:6|8|9|29))\.([0-9]{1,2})", + RegexOptions.Compiled); - /// - /// all information like e.g. is normalised to this reference time frame. - /// Must only be null if an error occurred and is not null. - /// - [JsonProperty(PropertyName = "referenceTimeFrame", Required = Required.AllowNull, Order = 7)] - public Zeitraum ReferenceTimeFrame { get; set; } + /// + /// all information like e.g. is normalised to this reference time frame. + /// Must only be null if an error occurred and is not null. + /// + [JsonProperty(PropertyName = "referenceTimeFrame", Required = Required.AllowNull, Order = 7)] + public Zeitraum ReferenceTimeFrame { get; set; } - /// - /// - /// - [DataCategory(DataCategory.POD)] - [JsonProperty(PropertyName = "lokationsId", Required = Required.Always, Order = 8)] - public string LokationsId { get; set; } + /// + /// + /// + [DataCategory(DataCategory.POD)] + [JsonProperty(PropertyName = "lokationsId", Required = Required.Always, Order = 8)] + public string LokationsId { get; set; } - /// - /// - /// - [JsonProperty(PropertyName = "obiskennzahl", Required = Required.Default, Order = 5)] - public string Obiskennzahl { get; set; } + /// + /// + /// + [JsonProperty(PropertyName = "obiskennzahl", Required = Required.Default, Order = 5)] + public string Obiskennzahl { get; set; } - /// - /// - /// - [JsonProperty(PropertyName = "einheit", Required = Required.Default, Order = 6)] - public Mengeneinheit Einheit { get; set; } + /// + /// + /// + [JsonProperty(PropertyName = "einheit", Required = Required.Default, Order = 6)] + public Mengeneinheit Einheit { get; set; } - /// - /// - /// - [JsonProperty(PropertyName = "wertermittlungsverfahren", Required = Required.Default, Order = 7)] - public Wertermittlungsverfahren? Wertermittlungsverfahren { get; set; } + /// + /// + /// + [JsonProperty(PropertyName = "wertermittlungsverfahren", Required = Required.Default, Order = 7)] + public Wertermittlungsverfahren? Wertermittlungsverfahren { get; set; } - /// - /// ratio of time with data present compared to . - /// 1.0 means 100% coverage. - /// - [JsonProperty(PropertyName = "coverage", Required = Required.AllowNull, Order = 8)] - public decimal? Coverage { get; set; } + /// + /// ratio of time with data present compared to . + /// 1.0 means 100% coverage. + /// + [JsonProperty(PropertyName = "coverage", Required = Required.AllowNull, Order = 8)] + public decimal? Coverage { get; set; } - /// - /// values - /// - [JsonProperty(PropertyName = "values", Required = Required.Default, Order = 5)] - [DataCategory(DataCategory.METER_READING)] - public List Values { get; set; } + /// + /// values + /// + [JsonProperty(PropertyName = "values", Required = Required.Default, Order = 5)] + [DataCategory(DataCategory.METER_READING)] + public List Values { get; set; } - /// - /// gaps are continous values () with value null. - /// - [JsonProperty(PropertyName = "gaps", Required = Required.Default, Order = 6)] - public List Gaps { get; set; } + /// + /// gaps are continous values () with value null. + /// + [JsonProperty(PropertyName = "gaps", Required = Required.Default, Order = 6)] + public List Gaps { get; set; } - /// - /// optional field for storing error messages - /// - [JsonProperty(PropertyName = "_errorMessage", Required = Required.Default)] - public string ErrorMessage { get; set; } + /// + /// optional field for storing error messages + /// + [JsonProperty(PropertyName = "_errorMessage", Required = Required.Default)] + public string ErrorMessage { get; set; } - // ToDo: make it nice. - /// - /// sorts two completeness reports such that those with earlier reference time are before others - /// - /// - /// - public int CompareTo(CompletenessReport other) + // ToDo: make it nice. + /// + /// sorts two completeness reports such that those with earlier reference time are before others + /// + /// + /// + public int CompareTo(CompletenessReport other) + { + if (ReferenceTimeFrame == null && other.ReferenceTimeFrame == null) { - if (ReferenceTimeFrame == null && other.ReferenceTimeFrame == null) + return 0; + } + + if (ReferenceTimeFrame != null && other.ReferenceTimeFrame == null) + { + return 1; + } + + if (ReferenceTimeFrame == null && other.ReferenceTimeFrame != null) + { + return -1; + } + + if (ReferenceTimeFrame != null && other.ReferenceTimeFrame != null) + { + if (ReferenceTimeFrame.Startdatum.HasValue && other.ReferenceTimeFrame.Startdatum.HasValue) { - return 0; + return Comparer.Default.Compare(ReferenceTimeFrame.Startdatum.Value, + other.ReferenceTimeFrame.Startdatum.Value); } - if (ReferenceTimeFrame != null && other.ReferenceTimeFrame == null) + if (ReferenceTimeFrame.Startdatum.HasValue) { return 1; } - if (ReferenceTimeFrame == null && other.ReferenceTimeFrame != null) - { - return -1; - } + return -1; + } + + return 0; + } - if (ReferenceTimeFrame != null && other.ReferenceTimeFrame != null) + /// + /// Convert CompletenessReport to CSV string + /// + /// Seperatur char for CSV items. By default is ';' + /// Shows header of columns in return string? + /// This value goes to end of every line. By default is "\\n" + /// + public string ToCSV(string separator = ";", bool headerLine = true, string lineTerminator = "\\n") + { + var builder = new StringBuilder(); + if (headerLine) + { + var headerColumns = new List { - if (ReferenceTimeFrame.Startdatum.HasValue && other.ReferenceTimeFrame.Startdatum.HasValue) - { - return Comparer.Default.Compare(ReferenceTimeFrame.Startdatum.Value, - other.ReferenceTimeFrame.Startdatum.Value); - } + "Startdatum", + "Enddatum", + "MeLo", + "MaLo", + "Messung", + "MSB", + "Profil-Nr.", + "Profil-Typ", + "Zeitbereich in dem kein wahrer Wert vorhanden ist von", + "Zeitbereich in dem kein wahrer Wert vorhanden ist bis", + "Anzahl fehlende Werte", + "Prozentuale Vollständigkeit", + "Status" + }; + builder.Append(string.Join(separator, headerColumns) + lineTerminator); + } - if (ReferenceTimeFrame.Startdatum.HasValue) - { - return 1; - } + var columns = new List + { + ReferenceTimeFrame.Startdatum.Value.ToString("yyyy-MM-ddTHH:mm:ssZ"), + ReferenceTimeFrame.Enddatum.Value.ToString("yyyy-MM-ddTHH:mm:ssZ") + }; - return -1; - } + if (Messlokation.ValidateId(LokationsId)) + { + columns.Add(LokationsId); // melo + columns.Add(string.Empty); // malo + } + else if (Marktlokation.ValidateId(LokationsId)) + { + columns.Add(string.Empty); //melo + columns.Add(LokationsId); //malo + } + else + { + // fallback only + columns.Add(LokationsId); + columns.Add(LokationsId); + } - return 0; + columns.Add(imsysRegex.Match(Obiskennzahl).Success ? "IMS" : "RLM"); // messung + columns.Add("MSB"); // MSB + + if (UserProperties.TryGetValue("profil", out var profil)) + { + columns.Add(profil.ToString()); + } + else + { + columns.Add(string.Empty); } - /// - /// Convert CompletenessReport to CSV string - /// - /// Seperatur char for CSV items. By default is ';' - /// Shows header of columns in return string? - /// This value goes to end of every line. By default is "\\n" - /// - public string ToCSV(string separator = ";", bool headerLine = true, string lineTerminator = "\\n") + if (UserProperties.TryGetValue("profilRolle", out var profilRolle)) { - var builder = new StringBuilder(); - if (headerLine) - { - var headerColumns = new List - { - "Startdatum", - "Enddatum", - "MeLo", - "MaLo", - "Messung", - "MSB", - "Profil-Nr.", - "Profil-Typ", - "Zeitbereich in dem kein wahrer Wert vorhanden ist von", - "Zeitbereich in dem kein wahrer Wert vorhanden ist bis", - "Anzahl fehlende Werte", - "Prozentuale Vollständigkeit", - "Status" - }; - builder.Append(string.Join(separator, headerColumns) + lineTerminator); - } + columns.Add(profilRolle.ToString()); + } + else + { + columns.Add(string.Empty); + } - var columns = new List - { - ReferenceTimeFrame.Startdatum.Value.ToString("yyyy-MM-ddTHH:mm:ssZ"), - ReferenceTimeFrame.Enddatum.Value.ToString("yyyy-MM-ddTHH:mm:ssZ") - }; + if (Gaps != null && Gaps.Any()) + { + var minGap = Gaps.Min(x => x.Startdatum); // OrderBy(x => x.Startdatum).First().Startdatum; + var maxGap = Gaps.Max(x => x.Enddatum); // OrderByDescending(x => x.Enddatum).First().Enddatum; + columns.Add(minGap.ToString("yyyy-MM-ddTHH:mm:ssZ")); + columns.Add(maxGap.ToString("yyyy-MM-ddTHH:mm:ssZ")); + var gapsHours = (maxGap - minGap).TotalHours; + columns.Add((gapsHours * 4).ToString(CultureInfo.InvariantCulture)); + } + else + { + columns.Add(string.Empty); + columns.Add(string.Empty); + columns.Add(string.Empty); + } - if (Messlokation.ValidateId(LokationsId)) - { - columns.Add(LokationsId); // melo - columns.Add(string.Empty); // malo - } - else if (Marktlokation.ValidateId(LokationsId)) - { - columns.Add(string.Empty); //melo - columns.Add(LokationsId); //malo - } - else - { - // fallback only - columns.Add(LokationsId); - columns.Add(LokationsId); - } + if (Coverage.HasValue) + { + columns.Add((Coverage.Value * 100).ToString("0.####") + " %"); + } + else + { + columns.Add(string.Empty); + } - columns.Add(imsysRegex.Match(Obiskennzahl).Success ? "IMS" : "RLM"); // messung - columns.Add("MSB"); // MSB + columns.Add("Status"); + builder.Append(string.Join(separator, columns) + lineTerminator); - if (UserProperties.TryGetValue("profil", out var profil)) - { - columns.Add(profil.ToString()); - } - else - { - columns.Add(string.Empty); - } + return builder.ToString(); + } - if (UserProperties.TryGetValue("profilRolle", out var profilRolle)) - { - columns.Add(profilRolle.ToString()); - } - else - { - columns.Add(string.Empty); - } + /// + /// similar to but with less obligatory values. + /// + // howto inherit from Verbrauch but change the JsonProperties? + public class BasicVerbrauch // : Verbrauch + { + /// + /// + /// + [JsonProperty(PropertyName = "startdatum", Required = Required.Always)] + public DateTime Startdatum { get; set; } - if (Gaps != null && Gaps.Any()) - { - var minGap = Gaps.Min(x => x.Startdatum); // OrderBy(x => x.Startdatum).First().Startdatum; - var maxGap = Gaps.Max(x => x.Enddatum); // OrderByDescending(x => x.Enddatum).First().Enddatum; - columns.Add(minGap.ToString("yyyy-MM-ddTHH:mm:ssZ")); - columns.Add(maxGap.ToString("yyyy-MM-ddTHH:mm:ssZ")); - var gapsHours = (maxGap - minGap).TotalHours; - columns.Add((gapsHours * 4).ToString(CultureInfo.InvariantCulture)); - } - else - { - columns.Add(string.Empty); - columns.Add(string.Empty); - columns.Add(string.Empty); - } + /// + /// + /// + [JsonProperty(PropertyName = "enddatum", Required = Required.Always)] + public DateTime Enddatum { get; set; } - if (Coverage.HasValue) - { - columns.Add((Coverage.Value * 100).ToString("0.####") + " %"); - } - else - { - columns.Add(string.Empty); - } + /// + /// . Make it null to express no value present. + /// + [DataCategory(DataCategory.METER_READING)] + [JsonProperty(PropertyName = "wert", Required = Required.AllowNull)] + public decimal? Wert { get; set; } - columns.Add("Status"); - builder.Append(string.Join(separator, columns) + lineTerminator); + /* + [JsonIgnore] + [JsonProperty(Required = Required.Default)] + private new readonly Wertermittlungsverfahren wertermittlungsverfahren; + + [JsonIgnore] + [JsonProperty(Required = Required.Default)] + private new readonly Mengeneinheit mengeneinheit; + + [JsonIgnore] + [JsonProperty(Required = Required.Default)] + private new readonly string obiskennzahl; + */ + } - return builder.ToString(); - } + /// + /// This data class contains all the parameters required to start the CompletenessReport generation. + /// It's easier to handle than four single parameters passed to the constructor of the CompletenessReport. + /// + public class CompletenessReportConfiguration + { + /// + /// reference time frame to be analysed + /// + [JsonProperty(PropertyName = "referenceTimeFrame", Required = Required.Always, Order = 7)] + public Zeitraum ReferenceTimeFrame { get; set; } /// - /// similar to but with less obligatory values. + /// Wertermittlungsverfahren () to be taken into account. /// - // howto inherit from Verbrauch but change the JsonProperties? - public class BasicVerbrauch // : Verbrauch - { - /// - /// - /// - [JsonProperty(PropertyName = "startdatum", Required = Required.Always)] - public DateTime Startdatum { get; set; } - - /// - /// - /// - [JsonProperty(PropertyName = "enddatum", Required = Required.Always)] - public DateTime Enddatum { get; set; } - - /// - /// . Make it null to express no value present. - /// - [DataCategory(DataCategory.METER_READING)] - [JsonProperty(PropertyName = "wert", Required = Required.AllowNull)] - public decimal? Wert { get; set; } - - /* - [JsonIgnore] - [JsonProperty(Required = Required.Default)] - private new readonly Wertermittlungsverfahren wertermittlungsverfahren; - - [JsonIgnore] - [JsonProperty(Required = Required.Default)] - private new readonly Mengeneinheit mengeneinheit; - - [JsonIgnore] - [JsonProperty(Required = Required.Default)] - private new readonly string obiskennzahl; - */ - } + [JsonProperty(PropertyName = "wertermittlungsverfahren", Required = Required.Default, Order = 8)] + public Wertermittlungsverfahren? Wertermittlungsverfahren { get; set; } /// - /// This data class contains all the parameters required to start the CompletenessReport generation. - /// It's easier to handle than four single parameters passed to the constructor of the CompletenessReport. + /// OBIS ID () to be taken into account. /// - public class CompletenessReportConfiguration - { - /// - /// reference time frame to be analysed - /// - [JsonProperty(PropertyName = "referenceTimeFrame", Required = Required.Always, Order = 7)] - public Zeitraum ReferenceTimeFrame { get; set; } - - /// - /// Wertermittlungsverfahren () to be taken into account. - /// - [JsonProperty(PropertyName = "wertermittlungsverfahren", Required = Required.Default, Order = 8)] - public Wertermittlungsverfahren? Wertermittlungsverfahren { get; set; } - - /// - /// OBIS ID () to be taken into account. - /// - [JsonProperty(PropertyName = "obis", Required = Required.Default, Order = 5)] - public string Obis { get; set; } - - /// - /// Unit () to be taken into account. - /// - [JsonProperty(PropertyName = "einheit", Required = Required.Default, Order = 6)] - public Mengeneinheit Einheit { get; set; } - } + [JsonProperty(PropertyName = "obis", Required = Required.Default, Order = 5)] + public string Obis { get; set; } - /* /// - /// allows sorting completeness reports based on + /// Unit () to be taken into account. /// - public class CompletenessReportComparer : IComparer + [JsonProperty(PropertyName = "einheit", Required = Required.Default, Order = 6)] + public Mengeneinheit Einheit { get; set; } + } + + /* + /// + /// allows sorting completeness reports based on + /// + public class CompletenessReportComparer : IComparer + { + public int Compare(CompletenessReport x, CompletenessReport y) { - public int Compare(CompletenessReport x, CompletenessReport y) + if (x.referenceTimeFrame != null && x.referenceTimeFrame.startdatum.HasValue && y.referenceTimeFrame != null && y.referenceTimeFrame.startdatum.HasValue) { - if (x.referenceTimeFrame != null && x.referenceTimeFrame.startdatum.HasValue && y.referenceTimeFrame != null && y.referenceTimeFrame.startdatum.HasValue) - { - return x.referenceTimeFrame.startdatum < y.referenceTimeFrame.startdatum ? 0 : 1; - } - else if (x.referenceTimeFrame != null && x.referenceTimeFrame.startdatum.HasValue) - { - return -1; - } - else - { - return x.referenceTimeFrame != null ? 0 : 1; - } + return x.referenceTimeFrame.startdatum < y.referenceTimeFrame.startdatum ? 0 : 1; } - }*/ - } + else if (x.referenceTimeFrame != null && x.referenceTimeFrame.startdatum.HasValue) + { + return -1; + } + else + { + return x.referenceTimeFrame != null ? 0 : 1; + } + } + }*/ } \ No newline at end of file diff --git a/BO4E.Reporting/PlausibilityReport.cs b/BO4E.Reporting/PlausibilityReport.cs index 1a2caab9..f873a6fb 100644 --- a/BO4E.Reporting/PlausibilityReport.cs +++ b/BO4E.Reporting/PlausibilityReport.cs @@ -4,93 +4,92 @@ using BO4E.meta; using Newtonsoft.Json; -namespace BO4E.Reporting +namespace BO4E.Reporting; + +/// +/// A plausibility report contains information about how likely it is that two objects of +/// of the type are actually from the same source. Typically +/// you'd like to compare Energiemenge from meter readings with different graining. +/// E.g. values that are transmitted periodically in 15minute intervals and isolated +/// readings. +/// +public class PlausibilityReport : Report { /// - /// A plausibility report contains information about how likely it is that two objects of - /// of the type are actually from the same source. Typically - /// you'd like to compare Energiemenge from meter readings with different graining. - /// E.g. values that are transmitted periodically in 15minute intervals and isolated - /// readings. + /// all information is normalised to this reference time frame /// - public class PlausibilityReport : Report - { - /// - /// all information is normalised to this reference time frame - /// - [JsonProperty(PropertyName = "referenceTimeFrame", Required = Required.Always, Order = 7)] - public Zeitraum ReferenceTimeFrame { get; set; } + [JsonProperty(PropertyName = "referenceTimeFrame", Required = Required.Always, Order = 7)] + public Zeitraum ReferenceTimeFrame { get; set; } - /// - /// refers to a - /// - [DataCategory(DataCategory.POD)] - [JsonProperty(PropertyName = "lokationsId", Required = Required.Always, Order = 8)] - public string LokationsId { get; set; } + /// + /// refers to a + /// + [DataCategory(DataCategory.POD)] + [JsonProperty(PropertyName = "lokationsId", Required = Required.Always, Order = 8)] + public string LokationsId { get; set; } - /// - /// relative deviation of both Energiemengen within . - /// Null iff the of is 0. - /// - /// - /// 0 = equal consumption - /// +1 = other Energiemenge has twice the consumption of the reference - /// -1 = other Energiemenge has 0 consumption - /// - [JsonProperty(PropertyName = "relativeDeviation", Required = Required.AllowNull, Order = 5)] - public decimal? RelativeDeviation { get; set; } + /// + /// relative deviation of both Energiemengen within . + /// Null iff the of is 0. + /// + /// + /// 0 = equal consumption + /// +1 = other Energiemenge has twice the consumption of the reference + /// -1 = other Energiemenge has 0 consumption + /// + [JsonProperty(PropertyName = "relativeDeviation", Required = Required.AllowNull, Order = 5)] + public decimal? RelativeDeviation { get; set; } - /// - /// Verbrauch of the reference Energiemenge - /// - [DataCategory(DataCategory.METER_READING)] - [JsonProperty(PropertyName = "verbrauchReference", Required = Required.Always, Order = 6)] - public Verbrauch VerbrauchReference { get; set; } + /// + /// Verbrauch of the reference Energiemenge + /// + [DataCategory(DataCategory.METER_READING)] + [JsonProperty(PropertyName = "verbrauchReference", Required = Required.Always, Order = 6)] + public Verbrauch VerbrauchReference { get; set; } - /// - /// Verbrauch of another Energiemenge - /// - [DataCategory(DataCategory.METER_READING)] - [JsonProperty(PropertyName = "verbrauchOther", Required = Required.Always, Order = 7)] - public Verbrauch VerbrauchOther { get; set; } + /// + /// Verbrauch of another Energiemenge + /// + [DataCategory(DataCategory.METER_READING)] + [JsonProperty(PropertyName = "verbrauchOther", Required = Required.Always, Order = 7)] + public Verbrauch VerbrauchOther { get; set; } + /// + /// absolute value of the difference between of and + /// + /// + [JsonProperty(PropertyName = "absoluteDeviation", Required = Required.Always, Order = 8)] + public decimal AbsoluteDeviation { get; set; } + + /// + /// unit of + /// + [JsonProperty(PropertyName = "absoluteDeviationEinheit", Required = Required.Always, Order = 5)] + public Mengeneinheit AbsoluteDeviationEinheit { get; set; } + + /// + /// This data class contains all the data required to start the PlausibilityReport generation. + /// It's easier to handle than four single parameters passed to the constructor of the Plausibility Report. + /// + public class PlausibilityReportConfiguration + { /// - /// absolute value of the difference between of and - /// + /// reference time frame /// - [JsonProperty(PropertyName = "absoluteDeviation", Required = Required.Always, Order = 8)] - public decimal AbsoluteDeviation { get; set; } + [JsonProperty(PropertyName = "timeframe", Required = Required.AllowNull)] + public Zeitraum Timeframe { get; set; } /// - /// unit of + /// Energiemenge to be compared with the reference Energiemenge /// - [JsonProperty(PropertyName = "absoluteDeviationEinheit", Required = Required.Always, Order = 5)] - public Mengeneinheit AbsoluteDeviationEinheit { get; set; } + [JsonProperty(PropertyName = "other", Required = Required.Always)] + public Energiemenge Other { get; set; } /// - /// This data class contains all the data required to start the PlausibilityReport generation. - /// It's easier to handle than four single parameters passed to the constructor of the Plausibility Report. + /// set true to ignore if Energiemenge do have different or + /// /// - public class PlausibilityReportConfiguration - { - /// - /// reference time frame - /// - [JsonProperty(PropertyName = "timeframe", Required = Required.AllowNull)] - public Zeitraum Timeframe { get; set; } - - /// - /// Energiemenge to be compared with the reference Energiemenge - /// - [JsonProperty(PropertyName = "other", Required = Required.Always)] - public Energiemenge Other { get; set; } - - /// - /// set true to ignore if Energiemenge do have different or - /// - /// - [JsonProperty(PropertyName = "ignoreLocation", Required = Required.Always)] - public bool IgnoreLocation { get; set; } - } + [JsonProperty(PropertyName = "ignoreLocation", Required = Required.Always)] + public bool IgnoreLocation { get; set; } } } \ No newline at end of file diff --git a/BO4E.Reporting/Report.cs b/BO4E.Reporting/Report.cs index 16eadf94..311cb156 100644 --- a/BO4E.Reporting/Report.cs +++ b/BO4E.Reporting/Report.cs @@ -6,120 +6,48 @@ using BO4E.BO; using static BO4E.Reporting.CompletenessReport; -namespace BO4E.Reporting +namespace BO4E.Reporting; + +/// +/// The base class of all reports. +/// The idea behind this BusinessObject and all derived classes is that heavy calculations +/// of interesting metrics is separated from displaying the data. Report BO acts as a intermediate +/// format between a BusinessObject extension methods and e.g. a Notification- or Plotting +/// service that can easily rely on the pre calculated values stored in a Report Object. +/// +public abstract class Report : BusinessObject { + // todo: add meta data like who created report and when... + // signatures or similar stuff. /// - /// The base class of all reports. - /// The idea behind this BusinessObject and all derived classes is that heavy calculations - /// of interesting metrics is separated from displaying the data. Report BO acts as a intermediate - /// format between a BusinessObject extension methods and e.g. a Notification- or Plotting - /// service that can easily rely on the pre calculated values stored in a Report Object. /// - public abstract class Report : BusinessObject + /// return report as CSV string + public string ToCsv(char separator = ';', bool headerLine = true, string lineTerminator = "\\n", + List> reihenfolge = null) { - // todo: add meta data like who created report and when... - // signatures or similar stuff. - /// - /// - /// return report as CSV string - public string ToCsv(char separator = ';', bool headerLine = true, string lineTerminator = "\\n", - List> reihenfolge = null) - { - var type = GetType(); - var resultBuilder = new StringBuilder(); - var result = new List(); - var headerNames = new List(); - var reterned = new Dictionary, List> { [headerNames] = result }; - reterned = Detect(type, separator, this, reterned); + var type = GetType(); + var resultBuilder = new StringBuilder(); + var result = new List(); + var headerNames = new List(); + var reterned = new Dictionary, List> { [headerNames] = result }; + reterned = Detect(type, separator, this, reterned); - headerNames = reterned.Keys.First(); - headerNames.AddRange(new List { "gap.startDatum", "gap.endDatum" }); - result = reterned.Values.First(); + headerNames = reterned.Keys.First(); + headerNames.AddRange(new List { "gap.startDatum", "gap.endDatum" }); + result = reterned.Values.First(); - var sortedResults = new List(); - var sortedHeaderNamesList = new List(); - var parallelItems = headerNames.GroupBy(x => x) - .Where(g => g.Count() > 1) - .Select(y => new { Element = y.Key, Counter = y.Count() }) - .ToList(); + var sortedResults = new List(); + var sortedHeaderNamesList = new List(); + var parallelItems = headerNames.GroupBy(x => x) + .Where(g => g.Count() > 1) + .Select(y => new { Element = y.Key, Counter = y.Count() }) + .ToList(); - if (parallelItems.Count > 0) - { - for (var i = 0; i < parallelItems.First().Counter; i++) - { - sortedResults.Clear(); - if (reihenfolge != null) - { - reihenfolge = reihenfolge.Where(x => x != null).ToList(); - foreach (var reihenItem in reihenfolge) - if (!string.IsNullOrEmpty(reihenItem.Values.First()) && - !string.IsNullOrEmpty(reihenItem.Keys.First())) - { - var index = headerNames.IndexOf(reihenItem.Keys.First()); - if (index != -1) - { - sortedHeaderNamesList.Add(reihenItem.Values.First()); - var curFieldName = reihenItem.Keys.First(); - if (parallelItems.Where(g => g.Element == curFieldName).Any()) - { - sortedResults.Add(result[index]); - var indx = headerNames.IndexOf(curFieldName); - headerNames.RemoveAt(indx); - result.RemoveAt(indx); - } - else - { - sortedResults.Add(result[index]); - } - } - else - { - throw new ArgumentException("invalid values", nameof(reihenfolge)); - } - } - else - { - throw new ArgumentNullException(nameof(reihenfolge)); - } - } - else - { - var userPropertiesIndex = headerNames.IndexOf("UserProperties"); - if (userPropertiesIndex >= 0) - { - headerNames.RemoveAt(userPropertiesIndex); - result.RemoveAt(userPropertiesIndex); - } - - //Values organize - var index = headerNames.IndexOf(parallelItems.First().Element); - if (i == 0) - { - headerNames.RemoveRange(index + 3, 3 * (parallelItems.First().Counter - 1)); - sortedHeaderNamesList.AddRange(headerNames); - } - - var valueIndex = index + i * 3; - var curValues = result.Skip(valueIndex).Take(3); - var startfix = result.Take(index); - var indexEndSection = index + 3 * parallelItems.First().Counter; - var endfix = result.Skip(indexEndSection).Take(result.Count - indexEndSection); - sortedResults.AddRange(startfix); - sortedResults.AddRange(curValues); - sortedResults.AddRange(endfix); - } - - if (i == 0 && headerLine) - { - resultBuilder = new StringBuilder(string.Join(separator.ToString(), sortedHeaderNamesList) + - lineTerminator); - } - - resultBuilder.Append(string.Join(separator.ToString(), sortedResults) + lineTerminator); - } - } - else + if (parallelItems.Count > 0) + { + for (var i = 0; i < parallelItems.First().Counter; i++) { + sortedResults.Clear(); if (reihenfolge != null) { reihenfolge = reihenfolge.Where(x => x != null).ToList(); @@ -131,13 +59,22 @@ public abstract class Report : BusinessObject if (index != -1) { sortedHeaderNamesList.Add(reihenItem.Values.First()); - sortedResults.Add(result[index]); + var curFieldName = reihenItem.Keys.First(); + if (parallelItems.Where(g => g.Element == curFieldName).Any()) + { + sortedResults.Add(result[index]); + var indx = headerNames.IndexOf(curFieldName); + headerNames.RemoveAt(indx); + result.RemoveAt(indx); + } + else + { + sortedResults.Add(result[index]); + } } else { - throw new ArgumentException( - $"'{reihenItem.Keys.First()}' was not part of {nameof(headerNames)}=[{string.Join(", ", headerNames)}]", - nameof(reihenfolge)); + throw new ArgumentException("invalid values", nameof(reihenfolge)); } } else @@ -154,180 +91,242 @@ public abstract class Report : BusinessObject result.RemoveAt(userPropertiesIndex); } - sortedHeaderNamesList.AddRange(headerNames); - sortedResults.AddRange(result); + //Values organize + var index = headerNames.IndexOf(parallelItems.First().Element); + if (i == 0) + { + headerNames.RemoveRange(index + 3, 3 * (parallelItems.First().Counter - 1)); + sortedHeaderNamesList.AddRange(headerNames); + } + + var valueIndex = index + i * 3; + var curValues = result.Skip(valueIndex).Take(3); + var startfix = result.Take(index); + var indexEndSection = index + 3 * parallelItems.First().Counter; + var endfix = result.Skip(indexEndSection).Take(result.Count - indexEndSection); + sortedResults.AddRange(startfix); + sortedResults.AddRange(curValues); + sortedResults.AddRange(endfix); } - if (headerLine) + if (i == 0 && headerLine) { - resultBuilder = - new StringBuilder(string.Join(separator.ToString(), sortedHeaderNamesList) + lineTerminator); + resultBuilder = new StringBuilder(string.Join(separator.ToString(), sortedHeaderNamesList) + + lineTerminator); } - resultBuilder.Append(string.Join(separator.ToString(), sortedResults)); + resultBuilder.Append(string.Join(separator.ToString(), sortedResults) + lineTerminator); } - - - var gapdata = new List(); - var gapHeaderNames = new List(); - var gapReterned = new Dictionary, List> { [gapHeaderNames] = gapdata }; - _ = DetectGaps(type, separator, this, gapReterned); - - var gapSortedResults = new List(); - var gapParallelItems = gapHeaderNames.GroupBy(x => x) - .Where(g => g.Count() > 1) - .Select(y => new { Element = y.Key, Counter = y.Count() }) - .ToList(); - if (gapParallelItems.Any()) + } + else + { + if (reihenfolge != null) { - for (var i = 0; i < gapParallelItems.First().Counter; i++) + reihenfolge = reihenfolge.Where(x => x != null).ToList(); + foreach (var reihenItem in reihenfolge) + if (!string.IsNullOrEmpty(reihenItem.Values.First()) && + !string.IsNullOrEmpty(reihenItem.Keys.First())) + { + var index = headerNames.IndexOf(reihenItem.Keys.First()); + if (index != -1) + { + sortedHeaderNamesList.Add(reihenItem.Values.First()); + sortedResults.Add(result[index]); + } + else + { + throw new ArgumentException( + $"'{reihenItem.Keys.First()}' was not part of {nameof(headerNames)}=[{string.Join(", ", headerNames)}]", + nameof(reihenfolge)); + } + } + else + { + throw new ArgumentNullException(nameof(reihenfolge)); + } + } + else + { + var userPropertiesIndex = headerNames.IndexOf("UserProperties"); + if (userPropertiesIndex >= 0) { - gapSortedResults.Clear(); - - var index = gapHeaderNames.IndexOf(gapParallelItems.First().Element); - var valueIndex = index + i * 2; - var curValues = gapdata.Skip(valueIndex).Take(2); - gapSortedResults.AddRange(curValues); - resultBuilder.Append(lineTerminator); - for (var z = 2; z < sortedHeaderNamesList.Count; z++) - resultBuilder.Append(separator.ToString()); - resultBuilder.Append(string.Join(separator.ToString(), gapSortedResults)); + headerNames.RemoveAt(userPropertiesIndex); + result.RemoveAt(userPropertiesIndex); } + + sortedHeaderNamesList.AddRange(headerNames); + sortedResults.AddRange(result); } - else + + if (headerLine) { - gapSortedResults.AddRange(gapdata); - resultBuilder.Append(separator + string.Join(separator.ToString(), gapSortedResults)); + resultBuilder = + new StringBuilder(string.Join(separator.ToString(), sortedHeaderNamesList) + lineTerminator); } - return resultBuilder.ToString(); + resultBuilder.Append(string.Join(separator.ToString(), sortedResults)); } - private Dictionary, List> Detect(Type type, char separator, object value, - Dictionary, List> returnData) + + var gapdata = new List(); + var gapHeaderNames = new List(); + var gapReterned = new Dictionary, List> { [gapHeaderNames] = gapdata }; + _ = DetectGaps(type, separator, this, gapReterned); + + var gapSortedResults = new List(); + var gapParallelItems = gapHeaderNames.GroupBy(x => x) + .Where(g => g.Count() > 1) + .Select(y => new { Element = y.Key, Counter = y.Count() }) + .ToList(); + if (gapParallelItems.Any()) + { + for (var i = 0; i < gapParallelItems.First().Counter; i++) + { + gapSortedResults.Clear(); + + var index = gapHeaderNames.IndexOf(gapParallelItems.First().Element); + var valueIndex = index + i * 2; + var curValues = gapdata.Skip(valueIndex).Take(2); + gapSortedResults.AddRange(curValues); + resultBuilder.Append(lineTerminator); + for (var z = 2; z < sortedHeaderNamesList.Count; z++) + resultBuilder.Append(separator.ToString()); + resultBuilder.Append(string.Join(separator.ToString(), gapSortedResults)); + } + } + else { - var props = type.GetProperties(); - var nonHiddenProps = props.Where(s => !s.Name.StartsWith("_")).ToList(); - var d = returnData.Values.First(); - var h = returnData.Keys.First(); - foreach (var field in nonHiddenProps) - if (field.PropertyType.IsSubclassOf(typeof(COM.COM))) + gapSortedResults.AddRange(gapdata); + resultBuilder.Append(separator + string.Join(separator.ToString(), gapSortedResults)); + } + + return resultBuilder.ToString(); + } + + private Dictionary, List> Detect(Type type, char separator, object value, + Dictionary, List> returnData) + { + var props = type.GetProperties(); + var nonHiddenProps = props.Where(s => !s.Name.StartsWith("_")).ToList(); + var d = returnData.Values.First(); + var h = returnData.Keys.First(); + foreach (var field in nonHiddenProps) + if (field.PropertyType.IsSubclassOf(typeof(COM.COM))) + { + returnData = Detect(field.PropertyType, separator, field.GetValue(value), returnData); + } + else if (field.PropertyType.IsGenericType && + field.PropertyType.GetGenericTypeDefinition() == typeof(List<>)) + { + if (field.GetValue(value) != null && field.Name != "gaps") { - returnData = Detect(field.PropertyType, separator, field.GetValue(value), returnData); + //var ItemType = field.GetValue(value).GetType().GetGenericArguments()[0]; + var list = field.GetValue(value); + var a = (IList)list; + foreach (var s in a) returnData = Detect(s.GetType(), separator, s, returnData); } - else if (field.PropertyType.IsGenericType && - field.PropertyType.GetGenericTypeDefinition() == typeof(List<>)) + } + else + { + var nestedValue = field.GetValue(value); + if (nestedValue != null) { - if (field.GetValue(value) != null && field.Name != "gaps") + var muterType = ""; + if (field.DeclaringType.BaseType == typeof(COM.COM)) { - //var ItemType = field.GetValue(value).GetType().GetGenericArguments()[0]; - var list = field.GetValue(value); - var a = (IList)list; - foreach (var s in a) returnData = Detect(s.GetType(), separator, s, returnData); + muterType = field.DeclaringType.Name + "."; } - } - else - { - var nestedValue = field.GetValue(value); - if (nestedValue != null) - { - var muterType = ""; - if (field.DeclaringType.BaseType == typeof(COM.COM)) - { - muterType = field.DeclaringType.Name + "."; - } - var val = nestedValue.ToString(); - if (field.PropertyType == typeof(DateTime?)) - { - if (((DateTime?)nestedValue).HasValue) - { - val = ((DateTime?)nestedValue).Value.ToString("yyyy-MM-ddTHH:mm:ssZ"); - } - } - else if (field.PropertyType == typeof(DateTimeOffset?)) - { - if (((DateTimeOffset?)nestedValue).HasValue) - { - val = ((DateTimeOffset?)nestedValue).Value.ToString("yyyy-MM-ddTHH:mm:ssZ"); - } - } - else if (field.PropertyType == typeof(DateTime)) + var val = nestedValue.ToString(); + if (field.PropertyType == typeof(DateTime?)) + { + if (((DateTime?)nestedValue).HasValue) { - val = ((DateTime)nestedValue).ToString("yyyy-MM-ddTHH:mm:ssZ"); + val = ((DateTime?)nestedValue).Value.ToString("yyyy-MM-ddTHH:mm:ssZ"); } - else if (field.PropertyType == typeof(DateTimeOffset)) + } + else if (field.PropertyType == typeof(DateTimeOffset?)) + { + if (((DateTimeOffset?)nestedValue).HasValue) { - val = ((DateTimeOffset)nestedValue).ToString("yyyy-MM-ddTHH:mm:ssZ"); + val = ((DateTimeOffset?)nestedValue).Value.ToString("yyyy-MM-ddTHH:mm:ssZ"); } - - h.Add(muterType + field.Name); - d.Add(val.Contains(separator) ? "\"" + val + "\"" : val); } + else if (field.PropertyType == typeof(DateTime)) + { + val = ((DateTime)nestedValue).ToString("yyyy-MM-ddTHH:mm:ssZ"); + } + else if (field.PropertyType == typeof(DateTimeOffset)) + { + val = ((DateTimeOffset)nestedValue).ToString("yyyy-MM-ddTHH:mm:ssZ"); + } + + h.Add(muterType + field.Name); + d.Add(val.Contains(separator) ? "\"" + val + "\"" : val); } + } - return returnData; - } + return returnData; + } - private Dictionary, List> DetectGaps(Type type, char separator, object value, - Dictionary, List> returnData) + private Dictionary, List> DetectGaps(Type type, char separator, object value, + Dictionary, List> returnData) + { + var fields = type.GetFields(); + var d = returnData.Values.First(); + var h = returnData.Keys.First(); + foreach (var field in fields) { - var fields = type.GetFields(); - var d = returnData.Values.First(); - var h = returnData.Keys.First(); - foreach (var field in fields) + if (field.FieldType.IsSubclassOf(typeof(COM.COM))) { - if (field.FieldType.IsSubclassOf(typeof(COM.COM))) - { - continue; - } + continue; + } - if (field.FieldType.IsGenericType && field.FieldType.GetGenericTypeDefinition() == typeof(List<>)) + if (field.FieldType.IsGenericType && field.FieldType.GetGenericTypeDefinition() == typeof(List<>)) + { + if (field.GetValue(value) != null && field.Name == "gaps") { - if (field.GetValue(value) != null && field.Name == "gaps") - { - var itemType = field.GetValue(value).GetType().GetGenericArguments()[0]; - var list = field.GetValue(value); - var a = (IList)list; - foreach (var s in a) returnData = DetectGaps(s.GetType(), separator, s, returnData); - } + var itemType = field.GetValue(value).GetType().GetGenericArguments()[0]; + var list = field.GetValue(value); + var a = (IList)list; + foreach (var s in a) returnData = DetectGaps(s.GetType(), separator, s, returnData); } - else + } + else + { + var nestedValue = field.GetValue(value); + if (nestedValue != null) { - var nestedValue = field.GetValue(value); - if (nestedValue != null) + if (field.DeclaringType.BaseType == typeof(COM.COM)) { - if (field.DeclaringType.BaseType == typeof(COM.COM)) - { - continue; - } + continue; + } - if (field.DeclaringType == typeof(BasicVerbrauch)) + if (field.DeclaringType == typeof(BasicVerbrauch)) + { + var muterType = "gap."; + var val = nestedValue.ToString(); + if (field.FieldType == typeof(DateTime?)) { - var muterType = "gap."; - var val = nestedValue.ToString(); - if (field.FieldType == typeof(DateTime?)) - { - if (((DateTime?)nestedValue).HasValue) - { - val = ((DateTime?)nestedValue).Value.ToString("yyyy-MM-ddTHH:mm:ssZ"); - } - - h.Add(muterType + field.Name); - d.Add(val.Contains(separator) ? "\"" + val + "\"" : val); - } - else if (field.FieldType == typeof(DateTime)) + if (((DateTime?)nestedValue).HasValue) { - val = ((DateTime)nestedValue).ToString("yyyy-MM-ddTHH:mm:ssZ"); - h.Add(muterType + field.Name); - d.Add(val.Contains(separator) ? "\"" + val + "\"" : val); + val = ((DateTime?)nestedValue).Value.ToString("yyyy-MM-ddTHH:mm:ssZ"); } + + h.Add(muterType + field.Name); + d.Add(val.Contains(separator) ? "\"" + val + "\"" : val); + } + else if (field.FieldType == typeof(DateTime)) + { + val = ((DateTime)nestedValue).ToString("yyyy-MM-ddTHH:mm:ssZ"); + h.Add(muterType + field.Name); + d.Add(val.Contains(separator) ? "\"" + val + "\"" : val); } } } } - - return returnData; } + + return returnData; } } \ No newline at end of file diff --git a/BO4ETestProject/CreateTimeZoneJson.cs b/BO4ETestProject/CreateTimeZoneJson.cs index 51c49a3e..b0edfbf9 100644 --- a/BO4ETestProject/CreateTimeZoneJson.cs +++ b/BO4ETestProject/CreateTimeZoneJson.cs @@ -2,34 +2,33 @@ using System.Text.Json; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace TestBO4E +namespace TestBO4E; + +/// +/// This class is just used to create a .resx file containing a serialized TimeZoneInfo object. +/// Details: https://docs.microsoft.com/en-us/dotnet/standard/datetime/save-time-zones-to-an-embedded-resource +/// +[TestClass] +public class CreateTimeZoneJson { - /// - /// This class is just used to create a .resx file containing a serialized TimeZoneInfo object. - /// Details: https://docs.microsoft.com/en-us/dotnet/standard/datetime/save-time-zones-to-an-embedded-resource - /// - [TestClass] - public class CreateTimeZoneJson - { - public const string ResxName = "western_europe_standard_time.resx"; + public const string ResxName = "western_europe_standard_time.resx"; - [TestMethod] - public void SerializeAsJson() + [TestMethod] + public void SerializeAsJson() + { + TimeZoneInfo tzi; + try { - TimeZoneInfo tzi; - try - { - tzi = TimeZoneInfo.FindSystemTimeZoneById("Central Europe Standard Time"); - } - catch (TimeZoneNotFoundException) - { - //Assert.IsTrue(false, "You cannot use this method on your machine."); // this occurs in github actions. it's ok. - return; - } - - Assert.IsTrue(tzi.SupportsDaylightSavingTime); - var json = JsonSerializer.Serialize(tzi); - Console.WriteLine(json); + tzi = TimeZoneInfo.FindSystemTimeZoneById("Central Europe Standard Time"); } + catch (TimeZoneNotFoundException) + { + //Assert.IsTrue(false, "You cannot use this method on your machine."); // this occurs in github actions. it's ok. + return; + } + + Assert.IsTrue(tzi.SupportsDaylightSavingTime); + var json = JsonSerializer.Serialize(tzi); + Console.WriteLine(json); } } \ No newline at end of file diff --git a/BO4ETestProject/TestAbstractDeserialization.cs b/BO4ETestProject/TestAbstractDeserialization.cs index 81e0411c..a7515b7c 100644 --- a/BO4ETestProject/TestAbstractDeserialization.cs +++ b/BO4ETestProject/TestAbstractDeserialization.cs @@ -7,102 +7,101 @@ using Newtonsoft.Json.Linq; using JsonSerializer = System.Text.Json.JsonSerializer; -namespace TestBO4E +namespace TestBO4E; + +[TestClass] +public class TestAbstractDeserialization { - [TestClass] - public class TestAbstractDeserialization + /// + /// Tests Abstract Deserialization using Newtonsoft.Json + /// + /// + [TestMethod] + public void TestMaLoDeserializationNewtonsoft() { - /// - /// Tests Abstract Deserialization using Newtonsoft.Json - /// - /// - [TestMethod] - public void TestMaLoDeserializationNewtonsoft() + JObject json; + using (var r = new StreamReader("BoMapperTests/marktlokation_simple.json")) { - JObject json; - using (var r = new StreamReader("BoMapperTests/marktlokation_simple.json")) - { - var jsonString = r.ReadToEnd(); - json = JObject.Parse(jsonString); - } - - var maloString = json["input"].ToString(); - var malo = JsonConvert.DeserializeObject(maloString); - Assert.IsNotNull(malo); - var bo = JsonConvert.DeserializeObject(maloString); - Assert.IsNotNull(bo); - Assert.IsInstanceOfType(bo, typeof(Marktlokation)); + var jsonString = r.ReadToEnd(); + json = JObject.Parse(jsonString); } - /// - /// Tests Abstract Deserialization using System.Text - /// - /// - [TestMethod] - public void TestMaLoDeserializationSystemText() + var maloString = json["input"].ToString(); + var malo = JsonConvert.DeserializeObject(maloString); + Assert.IsNotNull(malo); + var bo = JsonConvert.DeserializeObject(maloString); + Assert.IsNotNull(bo); + Assert.IsInstanceOfType(bo, typeof(Marktlokation)); + } + + /// + /// Tests Abstract Deserialization using System.Text + /// + /// + [TestMethod] + public void TestMaLoDeserializationSystemText() + { + JsonDocument json; + using (var r = new StreamReader("BoMapperTests/marktlokation_simple.json")) { - JsonDocument json; - using (var r = new StreamReader("BoMapperTests/marktlokation_simple.json")) - { - var jsonString = r.ReadToEnd(); - json = JsonDocument.Parse(jsonString); - } + var jsonString = r.ReadToEnd(); + json = JsonDocument.Parse(jsonString); + } - var options = LenientParsing.MOST_LENIENT.GetJsonSerializerOptions(); + var options = LenientParsing.MOST_LENIENT.GetJsonSerializerOptions(); - var maloString = json.RootElement.GetProperty("input").GetRawText(); - Assert.IsNotNull(maloString); - var malo = JsonSerializer.Deserialize(maloString, options); - Assert.IsNotNull(malo); - var bo = JsonSerializer.Deserialize(maloString, options); - Assert.IsNotNull(bo); - Assert.IsInstanceOfType(bo, typeof(Marktlokation)); - } + var maloString = json.RootElement.GetProperty("input").GetRawText(); + Assert.IsNotNull(maloString); + var malo = JsonSerializer.Deserialize(maloString, options); + Assert.IsNotNull(malo); + var bo = JsonSerializer.Deserialize(maloString, options); + Assert.IsNotNull(bo); + Assert.IsInstanceOfType(bo, typeof(Marktlokation)); + } - [TestMethod] - public void TestMaLoTypeNameHandlingDeserializationNewtonsoft() + [TestMethod] + public void TestMaLoTypeNameHandlingDeserializationNewtonsoft() + { + JObject json; + using (var r = new StreamReader("BoMapperTests/marktlokation_with_typenamehandling.json")) { - JObject json; - using (var r = new StreamReader("BoMapperTests/marktlokation_with_typenamehandling.json")) - { - var jsonString = r.ReadToEnd(); - json = JObject.Parse(jsonString); - } - - var settings = new JsonSerializerSettings - { - TypeNameHandling = TypeNameHandling.Objects - }; - var maloString = json["input"].ToString(); - var malo = JsonConvert.DeserializeObject(maloString, settings); - Assert.IsNotNull(malo); - var bo = JsonConvert.DeserializeObject(maloString, settings); - Assert.IsNotNull(bo); - Assert.IsInstanceOfType(bo, typeof(Marktlokation)); + var jsonString = r.ReadToEnd(); + json = JObject.Parse(jsonString); } - /// - /// similar to but with .NET5 - /// - [TestMethod] - public void TestMaLoDeserializationNet5() + var settings = new JsonSerializerSettings { - JsonDocument json; - using (var r = new StreamReader("BoMapperTests/marktlokation_simple.json")) - { - var jsonString = r.ReadToEnd(); - json = JsonDocument.Parse(jsonString); - } + TypeNameHandling = TypeNameHandling.Objects + }; + var maloString = json["input"].ToString(); + var malo = JsonConvert.DeserializeObject(maloString, settings); + Assert.IsNotNull(malo); + var bo = JsonConvert.DeserializeObject(maloString, settings); + Assert.IsNotNull(bo); + Assert.IsInstanceOfType(bo, typeof(Marktlokation)); + } - var options = LenientParsing.MOST_LENIENT.GetJsonSerializerOptions(); - var maloString = json.RootElement.GetProperty("input").GetRawText(); - var malo = JsonSerializer.Deserialize(maloString, options); - Assert.IsNotNull(malo); - var bo = JsonSerializer.Deserialize(maloString, options); - Assert.IsNotNull(bo); - Assert.IsInstanceOfType(bo, typeof(Marktlokation)); + /// + /// similar to but with .NET5 + /// + [TestMethod] + public void TestMaLoDeserializationNet5() + { + JsonDocument json; + using (var r = new StreamReader("BoMapperTests/marktlokation_simple.json")) + { + var jsonString = r.ReadToEnd(); + json = JsonDocument.Parse(jsonString); } - // no typename handling test in .NET as this is a JsonConvert feature + var options = LenientParsing.MOST_LENIENT.GetJsonSerializerOptions(); + var maloString = json.RootElement.GetProperty("input").GetRawText(); + var malo = JsonSerializer.Deserialize(maloString, options); + Assert.IsNotNull(malo); + var bo = JsonSerializer.Deserialize(maloString, options); + Assert.IsNotNull(bo); + Assert.IsInstanceOfType(bo, typeof(Marktlokation)); } + + // no typename handling test in .NET as this is a JsonConvert feature } \ No newline at end of file diff --git a/BO4ETestProject/TestAutoNumberConverter.cs b/BO4ETestProject/TestAutoNumberConverter.cs index b77ea8e3..654c8c11 100644 --- a/BO4ETestProject/TestAutoNumberConverter.cs +++ b/BO4ETestProject/TestAutoNumberConverter.cs @@ -5,27 +5,26 @@ using System.IO; using JsonSerializer = System.Text.Json.JsonSerializer; -namespace TestBO4E +namespace TestBO4E; + +[TestClass] +public class TestAutoNumberConverter { - [TestClass] - public class TestAutoNumberConverter - { - [TestMethod] - public void TestConverter() + [TestMethod] + public void TestConverter() + { + string jsonString; + using (var r = new StreamReader("testjsons/vertrag_numeric_versionstruktur.json")) { - string jsonString; - using (var r = new StreamReader("testjsons/vertrag_numeric_versionstruktur.json")) - { - jsonString = r.ReadToEnd(); + jsonString = r.ReadToEnd(); - } + } - var options = LenientParsing.MOST_LENIENT.GetJsonSerializerOptions(); + var options = LenientParsing.MOST_LENIENT.GetJsonSerializerOptions(); - var vertrag = JsonSerializer.Deserialize(jsonString, options); - Assert.IsNotNull(vertrag); - } + var vertrag = JsonSerializer.Deserialize(jsonString, options); + Assert.IsNotNull(vertrag); } } \ No newline at end of file diff --git a/BO4ETestProject/TestBOCOMDesign.cs b/BO4ETestProject/TestBOCOMDesign.cs index 536b3a8e..7805ee82 100644 --- a/BO4ETestProject/TestBOCOMDesign.cs +++ b/BO4ETestProject/TestBOCOMDesign.cs @@ -11,159 +11,158 @@ using System.Linq; using System.Reflection; -namespace TestBO4E +namespace TestBO4E; + +[TestClass] +public class TestBOCOMDesign { - [TestClass] - public class TestBOCOMDesign + private static readonly HashSet NO_KEYS_WHITELIST = new() { - private static readonly HashSet NO_KEYS_WHITELIST = new() - { - typeof(Kosten), - typeof(Wechsel) - }; + typeof(Kosten), + typeof(Wechsel) + }; - [TestMethod] - public void TestNoBOFields() + [TestMethod] + public void TestNoBOFields() + { + foreach (var type in typeof(BusinessObject).Assembly.GetTypes().Where(t => typeof(BusinessObject).IsAssignableFrom(t))) { - foreach (var type in typeof(BusinessObject).Assembly.GetTypes().Where(t => typeof(BusinessObject).IsAssignableFrom(t))) - { - var fields = type.GetFields().Where(f => f.IsPublic && !f.IsLiteral && !f.IsStatic); - Assert.IsFalse(fields.Any(), - $"Type {type} must not contain fields but has: {string.Join(", ", fields.ToList())}"); - } + var fields = type.GetFields().Where(f => f.IsPublic && !f.IsLiteral && !f.IsStatic); + Assert.IsFalse(fields.Any(), + $"Type {type} must not contain fields but has: {string.Join(", ", fields.ToList())}"); } + } - [TestMethod] - public void TestBoAllPublic() - { - foreach (var type in typeof(BusinessObject).Assembly.GetTypes().Where(t => t.BaseType == typeof(BusinessObject))) - Assert.IsTrue(type.IsPublic, - $"Type {type} is derived from {nameof(BusinessObject)} but is not public."); - } + [TestMethod] + public void TestBoAllPublic() + { + foreach (var type in typeof(BusinessObject).Assembly.GetTypes().Where(t => t.BaseType == typeof(BusinessObject))) + Assert.IsTrue(type.IsPublic, + $"Type {type} is derived from {nameof(BusinessObject)} but is not public."); + } - private static void AssertConsistentIgnores(Type type) + private static void AssertConsistentIgnores(Type type) + { + if (type.IsEnum) { - if (type.IsEnum) - { - // todo: write a test here - } - else - { - var newtonSoftIgnoredProperties = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance) - .Where(p => p.GetCustomAttributes(typeof(Newtonsoft.Json.JsonIgnoreAttribute)).Any()).ToHashSet(); - var systemTextIgnoreProperties = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance) - .Where(p => p.GetCustomAttributes(typeof(System.Text.Json.Serialization.JsonIgnoreAttribute)).Any()).ToHashSet(); - Assert.AreEqual(newtonSoftIgnoredProperties.Count, systemTextIgnoreProperties.Count, $"Type {type} has inconsistent JsonIgnores"); - // todo: name the properties in a useful error message - - var newtonSoftIgnoredFields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance) - .Where(p => p.GetCustomAttributes(typeof(Newtonsoft.Json.JsonIgnoreAttribute)).Any()).ToHashSet(); - var systemTextIgnoreFields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance) - .Where(p => p.GetCustomAttributes(typeof(System.Text.Json.Serialization.JsonIgnoreAttribute)).Any()).ToHashSet(); - Assert.AreEqual(newtonSoftIgnoredFields.Count, systemTextIgnoreFields.Count, $"Type {type} has inconsistent JsonIgnores"); - } + // todo: write a test here } - - [TestMethod] - public void TestConsistentIgnoresBo() + else { - foreach (var type in typeof(BusinessObject).Assembly.GetTypes().Where(t => t.BaseType == typeof(BusinessObject))) - { - AssertConsistentIgnores(type); - } + var newtonSoftIgnoredProperties = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance) + .Where(p => p.GetCustomAttributes(typeof(Newtonsoft.Json.JsonIgnoreAttribute)).Any()).ToHashSet(); + var systemTextIgnoreProperties = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance) + .Where(p => p.GetCustomAttributes(typeof(System.Text.Json.Serialization.JsonIgnoreAttribute)).Any()).ToHashSet(); + Assert.AreEqual(newtonSoftIgnoredProperties.Count, systemTextIgnoreProperties.Count, $"Type {type} has inconsistent JsonIgnores"); + // todo: name the properties in a useful error message + + var newtonSoftIgnoredFields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance) + .Where(p => p.GetCustomAttributes(typeof(Newtonsoft.Json.JsonIgnoreAttribute)).Any()).ToHashSet(); + var systemTextIgnoreFields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance) + .Where(p => p.GetCustomAttributes(typeof(System.Text.Json.Serialization.JsonIgnoreAttribute)).Any()).ToHashSet(); + Assert.AreEqual(newtonSoftIgnoredFields.Count, systemTextIgnoreFields.Count, $"Type {type} has inconsistent JsonIgnores"); } + } - [TestMethod] - public void TestConsistentIgnoresCom() + [TestMethod] + public void TestConsistentIgnoresBo() + { + foreach (var type in typeof(BusinessObject).Assembly.GetTypes().Where(t => t.BaseType == typeof(BusinessObject))) { - foreach (var type in typeof(COM).Assembly.GetTypes().Where(t => t.BaseType == typeof(COM))) - { - AssertConsistentIgnores(type); - } + AssertConsistentIgnores(type); } + } - [TestMethod] - public void TestNoCOMFields() + [TestMethod] + public void TestConsistentIgnoresCom() + { + foreach (var type in typeof(COM).Assembly.GetTypes().Where(t => t.BaseType == typeof(COM))) { - foreach (var type in typeof(COM).Assembly.GetTypes().Where(t => typeof(COM).IsAssignableFrom(t))) - { - var fields = type.GetFields().Where(f => f.IsPublic && !f.IsStatic); - Assert.IsFalse(fields.Any(), - $"Type {type} must not contain public fields but has: {string.Join(", ", fields.ToList())}"); - } + AssertConsistentIgnores(type); } + } - [TestMethod] - public void TestCOMAllPublic() + [TestMethod] + public void TestNoCOMFields() + { + foreach (var type in typeof(COM).Assembly.GetTypes().Where(t => typeof(COM).IsAssignableFrom(t))) { - foreach (var type in typeof(BusinessObject).Assembly.GetTypes().Where(t => t.BaseType == typeof(COM))) - Assert.IsTrue(type.IsPublic, $"Type {type} is derived from {nameof(COM)} but is not public."); + var fields = type.GetFields().Where(f => f.IsPublic && !f.IsStatic); + Assert.IsFalse(fields.Any(), + $"Type {type} must not contain public fields but has: {string.Join(", ", fields.ToList())}"); } + } - [TestMethod] - public void TestBoInheritance() - { - foreach (var type in typeof(BusinessObject).Assembly.GetTypes().Where(t => - t.IsClass && t.IsPublic && t.Namespace == "BO4E.BO" && !t.Name.EndsWith("Converter"))) - Assert.IsTrue(type.IsSubclassOf(typeof(BusinessObject)) || type == typeof(BusinessObject), - $"Type {type} does not inherit from {nameof(BusinessObject)}."); - } + [TestMethod] + public void TestCOMAllPublic() + { + foreach (var type in typeof(BusinessObject).Assembly.GetTypes().Where(t => t.BaseType == typeof(COM))) + Assert.IsTrue(type.IsPublic, $"Type {type} is derived from {nameof(COM)} but is not public."); + } - [TestMethod] - public void TestCOMInheritance() - { - foreach (var type in typeof(BusinessObject).Assembly.GetTypes().Where(t => - t.IsClass && t.IsPublic && t.Namespace == "BO4E.COM" && !t.Name.EndsWith("Converter"))) - Assert.IsTrue(type.IsSubclassOf(typeof(COM)) || type == typeof(COM), - $"Type {type} does not inherit from {nameof(COM)}."); - } + [TestMethod] + public void TestBoInheritance() + { + foreach (var type in typeof(BusinessObject).Assembly.GetTypes().Where(t => + t.IsClass && t.IsPublic && t.Namespace == "BO4E.BO" && !t.Name.EndsWith("Converter"))) + Assert.IsTrue(type.IsSubclassOf(typeof(BusinessObject)) || type == typeof(BusinessObject), + $"Type {type} does not inherit from {nameof(BusinessObject)}."); + } - [TestMethod] - public void TestEnumNamespace() - { - foreach (var type in - typeof(BusinessObject).Assembly.GetTypes().Where(t => t.IsPublic && t.Namespace == "BO4E.ENUM")) - Assert.IsTrue(type.IsEnum, - $"Type {type} is in namespace BO4E.ENUM but no enum! Consinder moving the definition to another namespace or adding an internal / private modifier."); - } + [TestMethod] + public void TestCOMInheritance() + { + foreach (var type in typeof(BusinessObject).Assembly.GetTypes().Where(t => + t.IsClass && t.IsPublic && t.Namespace == "BO4E.COM" && !t.Name.EndsWith("Converter"))) + Assert.IsTrue(type.IsSubclassOf(typeof(COM)) || type == typeof(COM), + $"Type {type} does not inherit from {nameof(COM)}."); + } + + [TestMethod] + public void TestEnumNamespace() + { + foreach (var type in + typeof(BusinessObject).Assembly.GetTypes().Where(t => t.IsPublic && t.Namespace == "BO4E.ENUM")) + Assert.IsTrue(type.IsEnum, + $"Type {type} is in namespace BO4E.ENUM but no enum! Consinder moving the definition to another namespace or adding an internal / private modifier."); + } - [TestMethod] - public void TestBoKeys() + [TestMethod] + public void TestBoKeys() + { + foreach (var type in typeof(BusinessObject).Assembly.GetTypes().Where(t => t.BaseType == typeof(BusinessObject) && !t.IsAbstract && !NO_KEYS_WHITELIST.Contains(t))) { - foreach (var type in typeof(BusinessObject).Assembly.GetTypes().Where(t => t.BaseType == typeof(BusinessObject) && !t.IsAbstract && !NO_KEYS_WHITELIST.Contains(t))) - { - var keyProps = type.GetProperties() - .Where(p => p.GetCustomAttributes(typeof(BoKey), false).Length > 0) - .OrderBy(ap => ap.GetCustomAttribute()?.Order) - .ToArray(); - Assert.IsTrue(keyProps.Any(), - $"Type {type} is derived from {nameof(BusinessObject)} but has no [{nameof(BoKey)}] attribute."); - } + var keyProps = type.GetProperties() + .Where(p => p.GetCustomAttributes(typeof(BoKey), false).Length > 0) + .OrderBy(ap => ap.GetCustomAttribute()?.Order) + .ToArray(); + Assert.IsTrue(keyProps.Any(), + $"Type {type} is derived from {nameof(BusinessObject)} but has no [{nameof(BoKey)}] attribute."); } + } - /// - /// There must be no fields in BusinessObjects or COMponents where you cannot distinguish no value (null) and initial - /// value (e.g. ENUM default values or integer 0) - /// - [TestMethod] - public void NullableDefaultEnums() + /// + /// There must be no fields in BusinessObjects or COMponents where you cannot distinguish no value (null) and initial + /// value (e.g. ENUM default values or integer 0) + /// + [TestMethod] + public void NullableDefaultEnums() + { + foreach (var boType in typeof(BusinessObject).Assembly.GetTypes().Where(t => (t.BaseType == typeof(BusinessObject) || t.BaseType == typeof(COM)) && !t.IsAbstract)) { - foreach (var boType in typeof(BusinessObject).Assembly.GetTypes().Where(t => (t.BaseType == typeof(BusinessObject) || t.BaseType == typeof(COM)) && !t.IsAbstract)) + foreach (var obligDefaultField in boType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance).Where(field => field.GetCustomAttributes(typeof(JsonPropertyAttribute), true).Cast().Any(jpa => jpa.Required == Required.Default))) { - foreach (var obligDefaultField in boType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance).Where(field => field.GetCustomAttributes(typeof(JsonPropertyAttribute), true).Cast().Any(jpa => jpa.Required == Required.Default))) + if (Nullable.GetUnderlyingType(obligDefaultField.PropertyType) != null || obligDefaultField.PropertyType == typeof(string)) + { + // it is already nullable. + continue; + } + if (!obligDefaultField.PropertyType.IsPrimitive && !obligDefaultField.PropertyType.IsEnum) { - if (Nullable.GetUnderlyingType(obligDefaultField.PropertyType) != null || obligDefaultField.PropertyType == typeof(string)) - { - // it is already nullable. - continue; - } - if (!obligDefaultField.PropertyType.IsPrimitive && !obligDefaultField.PropertyType.IsEnum) - { - continue; - } - Assert.IsTrue(false, $"The type {obligDefaultField.PropertyType} of {boType.FullName}.{obligDefaultField.Name} is not nullable but not marked as obligatory."); - // this is a problem because e.g. for integers you can't distinguish between no value (null) or initial value (0). Same is true for Enum values + continue; } + Assert.IsTrue(false, $"The type {obligDefaultField.PropertyType} of {boType.FullName}.{obligDefaultField.Name} is not nullable but not marked as obligatory."); + // this is a problem because e.g. for integers you can't distinguish between no value (null) or initial value (0). Same is true for Enum values } } } diff --git a/BO4ETestProject/TestBOCOMGuids.cs b/BO4ETestProject/TestBOCOMGuids.cs index 2981e8af..957c0b32 100644 --- a/BO4ETestProject/TestBOCOMGuids.cs +++ b/BO4ETestProject/TestBOCOMGuids.cs @@ -7,56 +7,55 @@ using Newtonsoft.Json; using JsonSerializer = System.Text.Json.JsonSerializer; -namespace TestBO4E +namespace TestBO4E; + +[TestClass] +public class TestBOCOMGuids { - [TestClass] - public class TestBOCOMGuids + [TestMethod] + public void TestBOGuidsNewtonsoft() { - [TestMethod] - public void TestBOGuidsNewtonsoft() + var em = new Energiemenge { - var em = new Energiemenge - { - LokationsId = "DE123456", - LokationsTyp = Lokationstyp.MALO, - Energieverbrauch = new List(), - Guid = Guid.NewGuid() - }; - - var emJson = JsonConvert.SerializeObject(em); - Assert.AreEqual(em.Guid.Value, JsonConvert.DeserializeObject(emJson).Guid.Value); - - var gp = new Geschaeftspartner - { - Gewerbekennzeichnung = true, - Guid = Guid.NewGuid() - }; - - var gpJson = JsonConvert.SerializeObject(gp); - Assert.AreEqual(gp.Guid.Value, JsonConvert.DeserializeObject(gpJson).Guid.Value); - } - - [TestMethod] - public void TestBOGuids() + LokationsId = "DE123456", + LokationsTyp = Lokationstyp.MALO, + Energieverbrauch = new List(), + Guid = Guid.NewGuid() + }; + + var emJson = JsonConvert.SerializeObject(em); + Assert.AreEqual(em.Guid.Value, JsonConvert.DeserializeObject(emJson).Guid.Value); + + var gp = new Geschaeftspartner { - var em = new Energiemenge - { - LokationsId = "DE123456", - LokationsTyp = Lokationstyp.MALO, - Energieverbrauch = new List(), - Guid = Guid.NewGuid() - }; - - var emJson = JsonSerializer.Serialize(em); - Assert.AreEqual(em.Guid.Value, JsonSerializer.Deserialize(emJson).Guid.Value); - var gp = new Geschaeftspartner - { - Gewerbekennzeichnung = true, - Guid = Guid.NewGuid() - }; - - var gpJson = JsonSerializer.Serialize(gp); - Assert.AreEqual(gp.Guid.Value, JsonSerializer.Deserialize(gpJson).Guid.Value); - } + Gewerbekennzeichnung = true, + Guid = Guid.NewGuid() + }; + + var gpJson = JsonConvert.SerializeObject(gp); + Assert.AreEqual(gp.Guid.Value, JsonConvert.DeserializeObject(gpJson).Guid.Value); + } + + [TestMethod] + public void TestBOGuids() + { + var em = new Energiemenge + { + LokationsId = "DE123456", + LokationsTyp = Lokationstyp.MALO, + Energieverbrauch = new List(), + Guid = Guid.NewGuid() + }; + + var emJson = JsonSerializer.Serialize(em); + Assert.AreEqual(em.Guid.Value, JsonSerializer.Deserialize(emJson).Guid.Value); + var gp = new Geschaeftspartner + { + Gewerbekennzeichnung = true, + Guid = Guid.NewGuid() + }; + + var gpJson = JsonSerializer.Serialize(gp); + Assert.AreEqual(gp.Guid.Value, JsonSerializer.Deserialize(gpJson).Guid.Value); } } \ No newline at end of file diff --git a/BO4ETestProject/TestBo4eUri.cs b/BO4ETestProject/TestBo4eUri.cs index 2687b99f..20ffa40b 100644 --- a/BO4ETestProject/TestBo4eUri.cs +++ b/BO4ETestProject/TestBo4eUri.cs @@ -9,227 +9,226 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; -namespace TestBO4E +namespace TestBO4E; + +[TestClass] +public class TestBo4eURI { - [TestClass] - public class TestBo4eURI + private static readonly Dictionary boNameResults = new Dictionary { - private static readonly Dictionary boNameResults = new Dictionary - { - {"bo4e://Marktlokation/987654321098", "Marktlokation"}, - {"bo4e://hurzelasdanoafi/123456", null}, - {"bo4e://Energiemenge/123456", "Energiemenge"}, - {"bo4e://Ansprechpartner/123467/adsadad/aafe4rq3rqr/", "Ansprechpartner"}, - {"bo4e://ansprechpartner/mitlowercase/", "Ansprechpartner"}, - {"bo4e://MaRkTLoKaTiOn/mitlowercase/", "Marktlokation"}, - {"bo4e://Marktlokation/?backendId=10000001308", "Marktlokation"} - }; - - private static readonly Dictionary> boKeyNamesResults = new Dictionary> + {"bo4e://Marktlokation/987654321098", "Marktlokation"}, + {"bo4e://hurzelasdanoafi/123456", null}, + {"bo4e://Energiemenge/123456", "Energiemenge"}, + {"bo4e://Ansprechpartner/123467/adsadad/aafe4rq3rqr/", "Ansprechpartner"}, + {"bo4e://ansprechpartner/mitlowercase/", "Ansprechpartner"}, + {"bo4e://MaRkTLoKaTiOn/mitlowercase/", "Marktlokation"}, + {"bo4e://Marktlokation/?backendId=10000001308", "Marktlokation"} + }; + + private static readonly Dictionary> boKeyNamesResults = new Dictionary> + { + {typeof(Marktlokation), new List {"marktlokationsId"}}, { - {typeof(Marktlokation), new List {"marktlokationsId"}}, - { - typeof(Messlokation), new List {"messlokationsId"} - } //<-- should be the json property name if annotated - }; + typeof(Messlokation), new List {"messlokationsId"} + } //<-- should be the json property name if annotated + }; - private static readonly Dictionary validationResults = new Dictionary - { - {"bo4e://Marktlokation/987654321098", true}, - // {" bo4e://Leerzeichen/987654321098", false }, - {"keinProtokoll/123456", false}, - {"falschesProtokoll://asdadadl/123456", false}, - {"bo4e://Marktlokation/123467/adsadad/aafe4rq3rqr/", true}, - {"bo4e://kf56@Marktlokation:100/adadsadad", true}, - {"bo4e://kf56:pw@Marktlokation:100/adadsadad?dasd=asd", true}, - {"bo4e://Marktlokation/123467/adsadad/aafe4rq3rqr?asdasda=3r343&adasdas=2334#341", true}, - {"bo4e://Marktteilnehmer/?backendId=1234", true} - }; - - [TestMethod] - public void TestUriConstructionAndKeyDeconstruction() + private static readonly Dictionary validationResults = new Dictionary + { + {"bo4e://Marktlokation/987654321098", true}, + // {" bo4e://Leerzeichen/987654321098", false }, + {"keinProtokoll/123456", false}, + {"falschesProtokoll://asdadadl/123456", false}, + {"bo4e://Marktlokation/123467/adsadad/aafe4rq3rqr/", true}, + {"bo4e://kf56@Marktlokation:100/adadsadad", true}, + {"bo4e://kf56:pw@Marktlokation:100/adadsadad?dasd=asd", true}, + {"bo4e://Marktlokation/123467/adsadad/aafe4rq3rqr?asdasda=3r343&adasdas=2334#341", true}, + {"bo4e://Marktteilnehmer/?backendId=1234", true} + }; + + [TestMethod] + public void TestUriConstructionAndKeyDeconstruction() + { + var files = Directory.GetFiles("bo4eURITests/", "*.json"); + foreach (var file in files) { - var files = Directory.GetFiles("bo4eURITests/", "*.json"); - foreach (var file in files) + JObject json; + using (var r = new StreamReader(file)) { - JObject json; - using (var r = new StreamReader(file)) - { - var jsonString = r.ReadToEnd(); - json = JsonConvert.DeserializeObject(jsonString); - } + var jsonString = r.ReadToEnd(); + json = JsonConvert.DeserializeObject(jsonString); + } - Assert.IsNotNull(json, $"The content of file {file} seems to be no valid JSON."); - Assert.IsNotNull(json["input"], $"The file {file} does not contain the mandatory 'input' key."); - Assert.IsNotNull(json["expectedUri"], - $"The file {file} does not contain the mandatory 'expectedUri' key."); - //string boType = (string)json["input"]["boTyp"]; - //Assert.IsNotNull(boType, $"The JSON content of file {file} is missing the obligatory 'boTyp' attribute."); - var bo = JsonConvert.DeserializeObject(json["input"].ToString()); - Assert.IsNotNull(bo, $"The business object in file {file} is not a valid BO4E."); - - var uri = Bo4eUri.GetUri(bo); - var uriString = uri.AbsoluteUri; - Assert.AreEqual(json["expectedUri"], uriString, "The URI doesn't match the expectations."); - - Assert.IsNotNull(json["expectedQueryObject"], - $"Please specify the query object result in file {file}, key 'expectedQueryObject'."); - var queryObject = uri.GetQueryObject(); - var jdp = new JsonDiffPatch(); - var left = json["expectedQueryObject"]; - JToken right = queryObject; - var patch = jdp.Diff(left, right); - if (patch != null) - { - if (patch.ToString() + Assert.IsNotNull(json, $"The content of file {file} seems to be no valid JSON."); + Assert.IsNotNull(json["input"], $"The file {file} does not contain the mandatory 'input' key."); + Assert.IsNotNull(json["expectedUri"], + $"The file {file} does not contain the mandatory 'expectedUri' key."); + //string boType = (string)json["input"]["boTyp"]; + //Assert.IsNotNull(boType, $"The JSON content of file {file} is missing the obligatory 'boTyp' attribute."); + var bo = JsonConvert.DeserializeObject(json["input"].ToString()); + Assert.IsNotNull(bo, $"The business object in file {file} is not a valid BO4E."); + + var uri = Bo4eUri.GetUri(bo); + var uriString = uri.AbsoluteUri; + Assert.AreEqual(json["expectedUri"], uriString, "The URI doesn't match the expectations."); + + Assert.IsNotNull(json["expectedQueryObject"], + $"Please specify the query object result in file {file}, key 'expectedQueryObject'."); + var queryObject = uri.GetQueryObject(); + var jdp = new JsonDiffPatch(); + var left = json["expectedQueryObject"]; + JToken right = queryObject; + var patch = jdp.Diff(left, right); + if (patch != null) + { + if (patch.ToString() .Replace("\n", "") .Replace("\r", "") .Replace(" ", "") == "{\"vorname\":[null,null]}") - { - continue; - } - - Assert.IsNull(patch, patch.ToString()); - } - else { - Assert.IsNull(patch); // witzlos. + continue; } - } - } - [TestMethod] - public void TestEmptyUriQueryObject() - { - var uri = new Bo4eUri("bo4e://Energiemenge"); - var exceptionThrown = false; - var result = string.Empty; - try - { - result = uri.GetQueryObject().ToString(); + Assert.IsNull(patch, patch.ToString()); } - catch (Exception) + else { - // must not happen! - exceptionThrown = true; + Assert.IsNull(patch); // witzlos. } - - Assert.IsFalse(exceptionThrown); - Assert.IsTrue(result.Contains("ENERGIEMENGE")); } + } - [TestMethod] - public void TestWellformedKannmichmal() + [TestMethod] + public void TestEmptyUriQueryObject() + { + var uri = new Bo4eUri("bo4e://Energiemenge"); + var exceptionThrown = false; + var result = string.Empty; + try { - var uri = new Bo4eUri( - "bo4e://messlokation/?filter=bilanzierungsmethode eq 'RLM'or bilanzierungsmethode eq 'IMS'"); - Assert.IsNotNull(uri); + result = uri.GetQueryObject().ToString(); } - - [TestMethod] - public void TestBoNamesAndTypes() + catch (Exception) { - foreach (var testString in boNameResults.Keys) - try - { - var uri = new Bo4eUri(testString); - Assert.AreEqual(boNameResults[testString], uri.GetBoName(), - $"boName validation failed for {testString}."); - Assert.IsTrue(uri.GetBoType().ToString().EndsWith(boNameResults[testString])); - } - catch (ArgumentException) - { - Assert.IsNull(boNameResults[testString]); - } + // must not happen! + exceptionThrown = true; } - [TestMethod] - public void TestBoKeyNames() - { - foreach (var boType in boKeyNamesResults.Keys) + Assert.IsFalse(exceptionThrown); + Assert.IsTrue(result.Contains("ENERGIEMENGE")); + } + + [TestMethod] + public void TestWellformedKannmichmal() + { + var uri = new Bo4eUri( + "bo4e://messlokation/?filter=bilanzierungsmethode eq 'RLM'or bilanzierungsmethode eq 'IMS'"); + Assert.IsNotNull(uri); + } + + [TestMethod] + public void TestBoNamesAndTypes() + { + foreach (var testString in boNameResults.Keys) + try { - var expectedList = boKeyNamesResults[boType]; - var actualList = BusinessObject.GetBoKeyNames(boType); - Assert.IsTrue(expectedList.SequenceEqual(actualList), - $"{boType}: expected: [{string.Join(",", expectedList)}] actual: [{string.Join(",", actualList)}] "); + var uri = new Bo4eUri(testString); + Assert.AreEqual(boNameResults[testString], uri.GetBoName(), + $"boName validation failed for {testString}."); + Assert.IsTrue(uri.GetBoType().ToString().EndsWith(boNameResults[testString])); } - } + catch (ArgumentException) + { + Assert.IsNull(boNameResults[testString]); + } + } - [TestMethod] - public void TestValidity() + [TestMethod] + public void TestBoKeyNames() + { + foreach (var boType in boKeyNamesResults.Keys) { - foreach (var testString in validationResults.Keys) - Assert.AreEqual(validationResults[testString], Bo4eUri.IsValid(testString), - $"URI validation failed for {testString} ."); + var expectedList = boKeyNamesResults[boType]; + var actualList = BusinessObject.GetBoKeyNames(boType); + Assert.IsTrue(expectedList.SequenceEqual(actualList), + $"{boType}: expected: [{string.Join(",", expectedList)}] actual: [{string.Join(",", actualList)}] "); } + } - [TestMethod] - public void TestUPInclusion() - { - var emString = - @"{'versionStruktur':1,'boTyp':'ENERGIEMENGE','lokationsId':'DE0000000000000000000000010000400','lokationstyp':'MeLo','zw':'000000000030000301','anlagennummer':'4000000199','messlokationsId':'DE0000000000000000000000010000400','marktlokationsId':''}"; - var em = JsonConvert.DeserializeObject(emString); - Assert.IsNotNull(em.UserProperties); - Assert.IsTrue(em.UserProperties.Keys.Count > 0); - var uri = em.GetURI(true); - Assert.IsTrue(uri.ToString().Contains("messlokationsId=")); - Assert.IsTrue(uri.ToString().Contains("anlagennummer=4000000199")); - } + [TestMethod] + public void TestValidity() + { + foreach (var testString in validationResults.Keys) + Assert.AreEqual(validationResults[testString], Bo4eUri.IsValid(testString), + $"URI validation failed for {testString} ."); + } - [TestMethod] - public void TestRoundTripUriFilterQueryObject() - { - var qo = JObject.Parse( - "{'marktlokationsId':'543212345', 'messlokationsId':'DE123', 'bilanzierungsmethode':'SLP'}"); - var uri = new Bo4eUri("bo4e://marktlokation?search=something").AddFilter( - JsonConvert.DeserializeObject>(qo.ToString())); - Assert.IsNotNull(uri); - Assert.AreEqual( - "bo4e://marktlokation/?search=something&filter=marktlokationsId+eq+%27543212345%27+and+bilanzierungsmethode+eq+%27SLP%27", - uri.ToString()); - var qo2 = uri.GetQueryObject(); - Assert.IsTrue(qo2.ContainsKey("marktlokationsId")); - Assert.IsTrue(qo2.ContainsKey("bilanzierungsmethode")); - Assert.AreEqual("543212345", qo2.GetValue("marktlokationsId")); - Assert.AreEqual("SLP", qo2.GetValue("bilanzierungsmethode")); - } + [TestMethod] + public void TestUPInclusion() + { + var emString = + @"{'versionStruktur':1,'boTyp':'ENERGIEMENGE','lokationsId':'DE0000000000000000000000010000400','lokationstyp':'MeLo','zw':'000000000030000301','anlagennummer':'4000000199','messlokationsId':'DE0000000000000000000000010000400','marktlokationsId':''}"; + var em = JsonConvert.DeserializeObject(emString); + Assert.IsNotNull(em.UserProperties); + Assert.IsTrue(em.UserProperties.Keys.Count > 0); + var uri = em.GetURI(true); + Assert.IsTrue(uri.ToString().Contains("messlokationsId=")); + Assert.IsTrue(uri.ToString().Contains("anlagennummer=4000000199")); + } - [TestMethod] - public void TestRLMFilter() - { - var uri = new Bo4eUri("bo4e://marktlokation?filter=bilanzierungsmethode%20%3D%20%27RLM%27"); - var query = uri.GetQueryObject(); - Assert.IsTrue(query.ContainsKey("bilanzierungsmethode")); - } + [TestMethod] + public void TestRoundTripUriFilterQueryObject() + { + var qo = JObject.Parse( + "{'marktlokationsId':'543212345', 'messlokationsId':'DE123', 'bilanzierungsmethode':'SLP'}"); + var uri = new Bo4eUri("bo4e://marktlokation?search=something").AddFilter( + JsonConvert.DeserializeObject>(qo.ToString())); + Assert.IsNotNull(uri); + Assert.AreEqual( + "bo4e://marktlokation/?search=something&filter=marktlokationsId+eq+%27543212345%27+and+bilanzierungsmethode+eq+%27SLP%27", + uri.ToString()); + var qo2 = uri.GetQueryObject(); + Assert.IsTrue(qo2.ContainsKey("marktlokationsId")); + Assert.IsTrue(qo2.ContainsKey("bilanzierungsmethode")); + Assert.AreEqual("543212345", qo2.GetValue("marktlokationsId")); + Assert.AreEqual("SLP", qo2.GetValue("bilanzierungsmethode")); + } - [TestMethod] - public void TestKlaerfallQueryObject() - { - /* - Bo4eUri uri1 = new Bo4eUri("bo4e://benachrichtigung/?filter=kategorie eq%20'ZE01' and erstellungsZeitpunkt eq '20190501142511'"); - var queryObject1 = uri1.GetQueryObject(); - Assert.IsTrue(queryObject1.ContainsKey("erstellungsZeitpunkt")); - Assert.IsTrue(queryObject1.ContainsKey("kategorie")); - */ - /* - Bo4eUri uri2 = new Bo4eUri("bo4e://benachrichtigung/?filter=kategorie eq 'ZE01' and erstellungsZeitpunkt lt '20190501142511'"); - var queryObject2 = uri2.GetQueryObject(); - Assert.IsTrue(queryObject2.ContainsKey("erstellungsZeitpunkt")); - Assert.IsTrue(queryObject2.ContainsKey("kategorie")); - */ - } + [TestMethod] + public void TestRLMFilter() + { + var uri = new Bo4eUri("bo4e://marktlokation?filter=bilanzierungsmethode%20%3D%20%27RLM%27"); + var query = uri.GetQueryObject(); + Assert.IsTrue(query.ContainsKey("bilanzierungsmethode")); + } - [TestMethod] - public void TestImplicitStringConversion() - { - Assert.IsTrue(ThisMethodOnlyAcceptsBo4eUri("bo4e://energiemenge?backendId=12345")); - } + [TestMethod] + public void TestKlaerfallQueryObject() + { + /* + Bo4eUri uri1 = new Bo4eUri("bo4e://benachrichtigung/?filter=kategorie eq%20'ZE01' and erstellungsZeitpunkt eq '20190501142511'"); + var queryObject1 = uri1.GetQueryObject(); + Assert.IsTrue(queryObject1.ContainsKey("erstellungsZeitpunkt")); + Assert.IsTrue(queryObject1.ContainsKey("kategorie")); + */ + /* + Bo4eUri uri2 = new Bo4eUri("bo4e://benachrichtigung/?filter=kategorie eq 'ZE01' and erstellungsZeitpunkt lt '20190501142511'"); + var queryObject2 = uri2.GetQueryObject(); + Assert.IsTrue(queryObject2.ContainsKey("erstellungsZeitpunkt")); + Assert.IsTrue(queryObject2.ContainsKey("kategorie")); + */ + } + + [TestMethod] + public void TestImplicitStringConversion() + { + Assert.IsTrue(ThisMethodOnlyAcceptsBo4eUri("bo4e://energiemenge?backendId=12345")); + } #pragma warning disable IDE0060 // Remove unused parameter - private bool ThisMethodOnlyAcceptsBo4eUri(Bo4eUri uri) + private bool ThisMethodOnlyAcceptsBo4eUri(Bo4eUri uri) #pragma warning restore IDE0060 // Remove unused parameter - { - return true; - } + { + return true; } } \ No newline at end of file diff --git a/BO4ETestProject/TestBoExpansion.cs b/BO4ETestProject/TestBoExpansion.cs index 2e270e02..ce0faa01 100644 --- a/BO4ETestProject/TestBoExpansion.cs +++ b/BO4ETestProject/TestBoExpansion.cs @@ -3,39 +3,38 @@ using BO4E.BO; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace TestBO4E +namespace TestBO4E; + +[TestClass] +public class TestBoExpansion { - [TestClass] - public class TestBoExpansion + [TestMethod] + public void TestBoExpansionMaLo() { - [TestMethod] - public void TestBoExpansionMaLo() - { - var result = new HashSet(BusinessObject.GetExpandablePropertyNames(typeof(Marktlokation)).Keys); - Assert.IsTrue(result.Contains("zugehoerigeMesslokationen")); + var result = new HashSet(BusinessObject.GetExpandablePropertyNames(typeof(Marktlokation)).Keys); + Assert.IsTrue(result.Contains("zugehoerigeMesslokationen")); - var result2 = new HashSet(BusinessObject.GetExpandableFieldNames("Marktlokation").Keys); - Assert.IsTrue(result.SetEquals(result2)); - Assert.ThrowsException(() => BusinessObject.GetExpandableFieldNames("kein gültiges bo")); - } + var result2 = new HashSet(BusinessObject.GetExpandableFieldNames("Marktlokation").Keys); + Assert.IsTrue(result.SetEquals(result2)); + Assert.ThrowsException(() => BusinessObject.GetExpandableFieldNames("kein gültiges bo")); + } - [TestMethod] - public void TestBoExpansionMeLo() - { - var result = new HashSet(BusinessObject.GetExpandablePropertyNames(typeof(Messlokation)).Keys); - Assert.IsTrue(result.Contains("messadresse")); - Assert.IsTrue(result.Contains("messlokationszaehler")); - Assert.IsTrue(result.Contains("messlokationszaehler.zaehlwerke")); - } + [TestMethod] + public void TestBoExpansionMeLo() + { + var result = new HashSet(BusinessObject.GetExpandablePropertyNames(typeof(Messlokation)).Keys); + Assert.IsTrue(result.Contains("messadresse")); + Assert.IsTrue(result.Contains("messlokationszaehler")); + Assert.IsTrue(result.Contains("messlokationszaehler.zaehlwerke")); + } - [TestMethod] - public void TestTypesEnergiemenge() - { - var result = BusinessObject.GetExpandablePropertyNames(typeof(Energiemenge)); - Assert.IsTrue(result.ContainsKey("energieverbrauch")); - var verbrauchsType = result["energieverbrauch"]; - Assert.IsTrue(verbrauchsType.IsGenericType); - Assert.IsTrue(verbrauchsType.GetGenericTypeDefinition() == typeof(List<>)); - } + [TestMethod] + public void TestTypesEnergiemenge() + { + var result = BusinessObject.GetExpandablePropertyNames(typeof(Energiemenge)); + Assert.IsTrue(result.ContainsKey("energieverbrauch")); + var verbrauchsType = result["energieverbrauch"]; + Assert.IsTrue(verbrauchsType.IsGenericType); + Assert.IsTrue(verbrauchsType.GetGenericTypeDefinition() == typeof(List<>)); } } \ No newline at end of file diff --git a/BO4ETestProject/TestEnergiemengeAdding.cs b/BO4ETestProject/TestEnergiemengeAdding.cs index 5feea29b..c20474e8 100644 --- a/BO4ETestProject/TestEnergiemengeAdding.cs +++ b/BO4ETestProject/TestEnergiemengeAdding.cs @@ -5,67 +5,66 @@ using BO4E.ENUM; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace TestBO4E +namespace TestBO4E; + +[TestClass] +public class TestEnergiemengeAdding { - [TestClass] - public class TestEnergiemengeAdding + [TestMethod] + public void TestSimpleAdd() { - [TestMethod] - public void TestSimpleAdd() + var em1 = new Energiemenge { - var em1 = new Energiemenge + LokationsId = "DE123", + LokationsTyp = Lokationstyp.MALO, + Energieverbrauch = new List { - LokationsId = "DE123", - LokationsTyp = Lokationstyp.MALO, - Energieverbrauch = new List + new Verbrauch { - new Verbrauch - { - Einheit = Mengeneinheit.ANZAHL, - Obiskennzahl = "1-2-3", - Enddatum = new DateTimeOffset(), - Startdatum = new DateTimeOffset(), - Wert = (decimal) 123.456, - Wertermittlungsverfahren = Wertermittlungsverfahren.PROGNOSE - } + Einheit = Mengeneinheit.ANZAHL, + Obiskennzahl = "1-2-3", + Enddatum = new DateTimeOffset(), + Startdatum = new DateTimeOffset(), + Wert = (decimal) 123.456, + Wertermittlungsverfahren = Wertermittlungsverfahren.PROGNOSE } - }; - var em2 = new Energiemenge + } + }; + var em2 = new Energiemenge + { + LokationsId = "DE123", + LokationsTyp = Lokationstyp.MALO, + Energieverbrauch = new List { - LokationsId = "DE123", - LokationsTyp = Lokationstyp.MALO, - Energieverbrauch = new List + new Verbrauch { - new Verbrauch - { - Einheit = Mengeneinheit.ANZAHL, - Obiskennzahl = "4-5-6", - Enddatum = new DateTimeOffset(), - Startdatum = new DateTimeOffset(), - Wert = (decimal) 123.456, - Wertermittlungsverfahren = Wertermittlungsverfahren.PROGNOSE - } + Einheit = Mengeneinheit.ANZAHL, + Obiskennzahl = "4-5-6", + Enddatum = new DateTimeOffset(), + Startdatum = new DateTimeOffset(), + Wert = (decimal) 123.456, + Wertermittlungsverfahren = Wertermittlungsverfahren.PROGNOSE } - }; - var result = em1 + em2; - Assert.IsNotNull(result); - Assert.AreEqual(2, result.Energieverbrauch.Count); - } + } + }; + var result = em1 + em2; + Assert.IsNotNull(result); + Assert.AreEqual(2, result.Energieverbrauch.Count); + } - [TestMethod] - public void TestIllegalAdd() + [TestMethod] + public void TestIllegalAdd() + { + var em1 = new Energiemenge { - var em1 = new Energiemenge - { - LokationsId = "DE456", - LokationsTyp = Lokationstyp.MELO - }; - var em2 = new Energiemenge - { - LokationsId = "DE789", - LokationsTyp = Lokationstyp.MELO - }; - Assert.ThrowsException(() => em1 + em2); - } + LokationsId = "DE456", + LokationsTyp = Lokationstyp.MELO + }; + var em2 = new Energiemenge + { + LokationsId = "DE789", + LokationsTyp = Lokationstyp.MELO + }; + Assert.ThrowsException(() => em1 + em2); } } \ No newline at end of file diff --git a/BO4ETestProject/TestEnergyIdentificationCodeExtensions.cs b/BO4ETestProject/TestEnergyIdentificationCodeExtensions.cs index e77ea4f7..c084689a 100644 --- a/BO4ETestProject/TestEnergyIdentificationCodeExtensions.cs +++ b/BO4ETestProject/TestEnergyIdentificationCodeExtensions.cs @@ -1,87 +1,86 @@ using BO4E.EnergyIdentificationCodes; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace TestBO4E +namespace TestBO4E; + +/// +/// Tests +/// +[TestClass] +public class TestEnergyIdentificationCodeExtensions { /// - /// Tests + /// Tests /// - [TestClass] - public class TestEnergyIdentificationCodeExtensions + /// + /// + [TestMethod] + [DataRow("", false)] + [DataRow(null, false)] + [DataRow("soooasdasdmk", false)] + [DataRow("11XRWENET12345-2", + true)] // example from section 7 https://eepublicdownloads.entsoe.eu/clean-documents/EDI/Library/cim_based/02%20EIC%20Code%20implementation%20guide_final.pdf + [DataRow("11XRWENET12345-3", + false)] // example from section 7 https://eepublicdownloads.entsoe.eu/clean-documents/EDI/Library/cim_based/02%20EIC%20Code%20implementation%20guide_final.pdf + // other examples taken from https://www.entsoe.eu/data/energy-identification-codes-eic/eic-approved-codes/ + [DataRow("10X1001A1001A361", true)] // TENNET_TSO + [DataRow("10X1001A1001A360", false)] // TENNET_TSO with wrong check sum + [DataRow("10X1001A1001A523", true)] // CYPRUS_TSO + [DataRow("10X1001A1001A524", false)] // CYPRUS_TSO with wrong check sum + [DataRow("59XEH1ALL9ORA116", true)] // CALORGAS ITALIA S.R.L. + [DataRow("59XEH1ALL9ORA117", false)] // CALORGAS ITALIA S.R.L. with wrong checksum + [DataRow("18XCONJH-12345-9", true)] // CONTRUCCIONES JAVIER HERRAN, S.L. + [DataRow("18XCONJH-12345-0", false)] // CONTRUCCIONES JAVIER HERRAN, S.L. with wrong checksum + public void TestEICValidity(string eicCode, bool expectedValidity) { - /// - /// Tests - /// - /// - /// - [TestMethod] - [DataRow("", false)] - [DataRow(null, false)] - [DataRow("soooasdasdmk", false)] - [DataRow("11XRWENET12345-2", - true)] // example from section 7 https://eepublicdownloads.entsoe.eu/clean-documents/EDI/Library/cim_based/02%20EIC%20Code%20implementation%20guide_final.pdf - [DataRow("11XRWENET12345-3", - false)] // example from section 7 https://eepublicdownloads.entsoe.eu/clean-documents/EDI/Library/cim_based/02%20EIC%20Code%20implementation%20guide_final.pdf - // other examples taken from https://www.entsoe.eu/data/energy-identification-codes-eic/eic-approved-codes/ - [DataRow("10X1001A1001A361", true)] // TENNET_TSO - [DataRow("10X1001A1001A360", false)] // TENNET_TSO with wrong check sum - [DataRow("10X1001A1001A523", true)] // CYPRUS_TSO - [DataRow("10X1001A1001A524", false)] // CYPRUS_TSO with wrong check sum - [DataRow("59XEH1ALL9ORA116", true)] // CALORGAS ITALIA S.R.L. - [DataRow("59XEH1ALL9ORA117", false)] // CALORGAS ITALIA S.R.L. with wrong checksum - [DataRow("18XCONJH-12345-9", true)] // CONTRUCCIONES JAVIER HERRAN, S.L. - [DataRow("18XCONJH-12345-0", false)] // CONTRUCCIONES JAVIER HERRAN, S.L. with wrong checksum - public void TestEICValidity(string eicCode, bool expectedValidity) - { - var actualValidity = eicCode.IsValidEIC(); - Assert.AreEqual(expected: expectedValidity, actual: actualValidity); - } + var actualValidity = eicCode.IsValidEIC(); + Assert.AreEqual(expected: expectedValidity, actual: actualValidity); + } - /// - /// Tests - /// - /// - /// - [TestMethod] - [DataRow("foobar", false)] - [DataRow("18XCONJH-12345-9", false)] // CONTRUCCIONES JAVIER HERRAN, S.L. is not BDEW managed - [DataRow("11YW-WALLDUERN-L", true)] // Stadtwerke Walldürn GmbH - [DataRow("11YW-FAS-------D", true)] // EGC Infrastruktur und Netz GmbH - [DataRow("11YW-HIRSCHBERKK", true)] // Netzbetrieb Hirschberg GmbH & Co. KG - public void TestEICBdew(string eicCode, bool expectedValidity) - { - var actualValidity = eicCode.IsValidEICBDEW(); - Assert.AreEqual(expected: expectedValidity, actual: actualValidity); - } + /// + /// Tests + /// + /// + /// + [TestMethod] + [DataRow("foobar", false)] + [DataRow("18XCONJH-12345-9", false)] // CONTRUCCIONES JAVIER HERRAN, S.L. is not BDEW managed + [DataRow("11YW-WALLDUERN-L", true)] // Stadtwerke Walldürn GmbH + [DataRow("11YW-FAS-------D", true)] // EGC Infrastruktur und Netz GmbH + [DataRow("11YW-HIRSCHBERKK", true)] // Netzbetrieb Hirschberg GmbH & Co. KG + public void TestEICBdew(string eicCode, bool expectedValidity) + { + var actualValidity = eicCode.IsValidEICBDEW(); + Assert.AreEqual(expected: expectedValidity, actual: actualValidity); + } - /// - /// Tests - /// - [TestMethod] - [DataRow("foo bar", false)] - [DataRow("11YW-FAS-------D", true)] // EGC Infrastruktur und Netz GmbH - [DataRow("11YW-HIRSCHBERKK", true)] // Netzbetrieb Hirschberg GmbH & Co. KG - [DataRow("11XVER-SWHEI---3", false)] // Stadtwerke Heide are not a Bilanzierungsgebiet - public void TestBilanzierungsgebietValidity(string eicCode, bool expectedValidity) - { - var actualValidity = eicCode.IsValidBilanzierungsGebietId(); - Assert.AreEqual(expected: expectedValidity, actual: actualValidity); - } + /// + /// Tests + /// + [TestMethod] + [DataRow("foo bar", false)] + [DataRow("11YW-FAS-------D", true)] // EGC Infrastruktur und Netz GmbH + [DataRow("11YW-HIRSCHBERKK", true)] // Netzbetrieb Hirschberg GmbH & Co. KG + [DataRow("11XVER-SWHEI---3", false)] // Stadtwerke Heide are not a Bilanzierungsgebiet + public void TestBilanzierungsgebietValidity(string eicCode, bool expectedValidity) + { + var actualValidity = eicCode.IsValidBilanzierungsGebietId(); + Assert.AreEqual(expected: expectedValidity, actual: actualValidity); + } - /// - /// Tests - /// - /// - /// - [TestMethod] - [DataRow("10YDE-EON------1", true)] - [DataRow("10YDE-RWENET---I", true)] - [DataRow("10YDE-VE-------2", true)] - [DataRow("10YDE-ENBW-----N", true)] - [DataRow("foobar", false)] - public void TestGermanRegelZone(string eicCode, bool expectedValidity) - { - Assert.AreEqual(expectedValidity, eicCode.IsGermanControlArea()); - } + /// + /// Tests + /// + /// + /// + [TestMethod] + [DataRow("10YDE-EON------1", true)] + [DataRow("10YDE-RWENET---I", true)] + [DataRow("10YDE-VE-------2", true)] + [DataRow("10YDE-ENBW-----N", true)] + [DataRow("foobar", false)] + public void TestGermanRegelZone(string eicCode, bool expectedValidity) + { + Assert.AreEqual(expectedValidity, eicCode.IsGermanControlArea()); } } \ No newline at end of file diff --git a/BO4ETestProject/TestEnumMembers.cs b/BO4ETestProject/TestEnumMembers.cs index b3da735d..554d8c85 100644 --- a/BO4ETestProject/TestEnumMembers.cs +++ b/BO4ETestProject/TestEnumMembers.cs @@ -8,65 +8,64 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json.Converters; -namespace TestBO4E +namespace TestBO4E; + +[TestClass] +public class TestEnumMembers { - [TestClass] - public class TestEnumMembers + /// + /// Tests that every enum member has an EnumMemberAttribute whose value matches the field name itself. + /// + /// This is to make the enums compatible with https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/1162 + [TestMethod] + public void TestEnumMemberConsistency() { - /// - /// Tests that every enum member has an EnumMemberAttribute whose value matches the field name itself. - /// - /// This is to make the enums compatible with https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/1162 - [TestMethod] - public void TestEnumMemberConsistency() + var enumTypes = typeof(AbgabeArt).Assembly.GetTypes() + .Where(t => t.IsEnum && t.Namespace.StartsWith("BO4E.ENUM") && + !t.Namespace.StartsWith("BO4E.ENUM.EDI")); + foreach (var enumType in enumTypes) { - var enumTypes = typeof(AbgabeArt).Assembly.GetTypes() - .Where(t => t.IsEnum && t.Namespace.StartsWith("BO4E.ENUM") && - !t.Namespace.StartsWith("BO4E.ENUM.EDI")); - foreach (var enumType in enumTypes) - { - var enumFields = enumType.GetFields() - .Where(f => f.IsPublic) - .Where(f => f.Name != "value__") - .ToList(); - var fieldsWithoutEnumMemberAttributes = enumFields - .Where(f => !f.GetCustomAttributes().Any()) - .Select(f => new Tuple(enumType, f.Name)); - fieldsWithoutEnumMemberAttributes.Should().BeEmpty(); - var enumMemberAttributeDiffersFromEnumMemberName = enumFields - .Select(f => new Tuple(f.GetCustomAttribute().Value, f.Name)) - .Where(nameTuple => nameTuple.Item1 != nameTuple.Item2); - enumMemberAttributeDiffersFromEnumMemberName.Should().BeEmpty(); - } + var enumFields = enumType.GetFields() + .Where(f => f.IsPublic) + .Where(f => f.Name != "value__") + .ToList(); + var fieldsWithoutEnumMemberAttributes = enumFields + .Where(f => !f.GetCustomAttributes().Any()) + .Select(f => new Tuple(enumType, f.Name)); + fieldsWithoutEnumMemberAttributes.Should().BeEmpty(); + var enumMemberAttributeDiffersFromEnumMemberName = enumFields + .Select(f => new Tuple(f.GetCustomAttribute().Value, f.Name)) + .Where(nameTuple => nameTuple.Item1 != nameTuple.Item2); + enumMemberAttributeDiffersFromEnumMemberName.Should().BeEmpty(); } + } - internal class MyClass - { - public Verwendungszweck Verwendungszweck { get; set; } - } + internal class MyClass + { + public Verwendungszweck Verwendungszweck { get; set; } + } - [TestMethod] - public void Test_Mehrmindermengenabrechnung_System_Text() - { - var options = LenientParsing.MOST_LENIENT.GetJsonSerializerOptions(); - var myLegacyInstance = new MyClass() { Verwendungszweck = Verwendungszweck.MEHRMINDERMENGENABRECHNUNG }; - var myLegacyJson = System.Text.Json.JsonSerializer.Serialize(myLegacyInstance, options); - myLegacyJson.Should().Contain("MEHRMINDERMENGENABRECHNUNG"); - var myNewInstance = System.Text.Json.JsonSerializer.Deserialize(myLegacyJson, options); - myNewInstance.Verwendungszweck.Should().Be(Verwendungszweck.MEHRMINDERMENGENABRECHNUNG); - } + [TestMethod] + public void Test_Mehrmindermengenabrechnung_System_Text() + { + var options = LenientParsing.MOST_LENIENT.GetJsonSerializerOptions(); + var myLegacyInstance = new MyClass() { Verwendungszweck = Verwendungszweck.MEHRMINDERMENGENABRECHNUNG }; + var myLegacyJson = System.Text.Json.JsonSerializer.Serialize(myLegacyInstance, options); + myLegacyJson.Should().Contain("MEHRMINDERMENGENABRECHNUNG"); + var myNewInstance = System.Text.Json.JsonSerializer.Deserialize(myLegacyJson, options); + myNewInstance.Verwendungszweck.Should().Be(Verwendungszweck.MEHRMINDERMENGENABRECHNUNG); + } - [TestMethod] - public void Test_Mehrmindermengenabrechnung_Newtonsoft() - { - var options = LenientParsing.MOST_LENIENT.GetJsonSerializerSettings(); - options.Converters.Add(new StringEnumConverter()); - var myLegacyInstance = new MyClass() { Verwendungszweck = Verwendungszweck.MEHRMINDERMENGENABRECHNUNG }; - var myLegacyJson = Newtonsoft.Json.JsonConvert.SerializeObject(myLegacyInstance, options); - myLegacyJson.Should().Contain("MEHRMINDERMENGENABRECHNUNG"); - var myNewInstance = Newtonsoft.Json.JsonConvert.DeserializeObject(myLegacyJson, options); - myNewInstance.Verwendungszweck.Should().Be(Verwendungszweck.MEHRMINDERMENGENABRECHNUNG); - } + [TestMethod] + public void Test_Mehrmindermengenabrechnung_Newtonsoft() + { + var options = LenientParsing.MOST_LENIENT.GetJsonSerializerSettings(); + options.Converters.Add(new StringEnumConverter()); + var myLegacyInstance = new MyClass() { Verwendungszweck = Verwendungszweck.MEHRMINDERMENGENABRECHNUNG }; + var myLegacyJson = Newtonsoft.Json.JsonConvert.SerializeObject(myLegacyInstance, options); + myLegacyJson.Should().Contain("MEHRMINDERMENGENABRECHNUNG"); + var myNewInstance = Newtonsoft.Json.JsonConvert.DeserializeObject(myLegacyJson, options); + myNewInstance.Verwendungszweck.Should().Be(Verwendungszweck.MEHRMINDERMENGENABRECHNUNG); } -} +} \ No newline at end of file diff --git a/BO4ETestProject/TestExterneReferenzen.cs b/BO4ETestProject/TestExterneReferenzen.cs index aab7a531..f07b5167 100644 --- a/BO4ETestProject/TestExterneReferenzen.cs +++ b/BO4ETestProject/TestExterneReferenzen.cs @@ -4,48 +4,47 @@ using BO4E.COM; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace TestBO4E +namespace TestBO4E; + +[TestClass] +public class TestExterneReferenzen { - [TestClass] - public class TestExterneReferenzen + [TestMethod] + public void TestGettingAndSetting() { - [TestMethod] - public void TestGettingAndSetting() + var marktlokation = new Marktlokation { - var marktlokation = new Marktlokation - { - MarktlokationsId = "54321012345" - }; - Assert.IsFalse(marktlokation.TryGetExterneReferenz("foo", out var _)); - marktlokation.ExterneReferenzen = new List(); - Assert.IsFalse(marktlokation.TryGetExterneReferenz("foo", out var _)); - marktlokation.ExterneReferenzen.Add(new ExterneReferenz { ExRefName = "foo", ExRefWert = "bar" }); - Assert.IsTrue(marktlokation.TryGetExterneReferenz("foo", out var actualBar)); - Assert.AreEqual("bar", actualBar); + MarktlokationsId = "54321012345" + }; + Assert.IsFalse(marktlokation.TryGetExterneReferenz("foo", out var _)); + marktlokation.ExterneReferenzen = new List(); + Assert.IsFalse(marktlokation.TryGetExterneReferenz("foo", out var _)); + marktlokation.ExterneReferenzen.Add(new ExterneReferenz { ExRefName = "foo", ExRefWert = "bar" }); + Assert.IsTrue(marktlokation.TryGetExterneReferenz("foo", out var actualBar)); + Assert.AreEqual("bar", actualBar); - Assert.ThrowsException( - () => marktlokation.SetExterneReferenz(new ExterneReferenz { ExRefName = null, ExRefWert = "nicht bar" }), - "must not add invalid values"); - Assert.ThrowsException( - () => marktlokation.SetExterneReferenz(new ExterneReferenz { ExRefName = "foo", ExRefWert = null }), - "must not add invalid values"); - Assert.ThrowsException(() => marktlokation.SetExterneReferenz(null), - "must not add null"); + Assert.ThrowsException( + () => marktlokation.SetExterneReferenz(new ExterneReferenz { ExRefName = null, ExRefWert = "nicht bar" }), + "must not add invalid values"); + Assert.ThrowsException( + () => marktlokation.SetExterneReferenz(new ExterneReferenz { ExRefName = "foo", ExRefWert = null }), + "must not add invalid values"); + Assert.ThrowsException(() => marktlokation.SetExterneReferenz(null), + "must not add null"); - Assert.ThrowsException( - () => marktlokation.SetExterneReferenz(new ExterneReferenz - { ExRefName = "foo", ExRefWert = "nicht bar" }), "By default conflicting values are rejected"); - marktlokation.SetExterneReferenz(new ExterneReferenz { ExRefName = "foo", ExRefWert = "nicht bar" }, true); - Assert.IsTrue(marktlokation.TryGetExterneReferenz("foo", out actualBar)); - Assert.AreNotEqual("bar", actualBar); + Assert.ThrowsException( + () => marktlokation.SetExterneReferenz(new ExterneReferenz + { ExRefName = "foo", ExRefWert = "nicht bar" }), "By default conflicting values are rejected"); + marktlokation.SetExterneReferenz(new ExterneReferenz { ExRefName = "foo", ExRefWert = "nicht bar" }, true); + Assert.IsTrue(marktlokation.TryGetExterneReferenz("foo", out actualBar)); + Assert.AreNotEqual("bar", actualBar); - marktlokation.ExterneReferenzen = null; - marktlokation.SetExterneReferenz(new ExterneReferenz - { ExRefName = "foo", ExRefWert = "bar" }); // if null, list is automatically created - marktlokation.SetExterneReferenz(new ExterneReferenz - { ExRefName = "foo", ExRefWert = "bar" }); // setting a non-conflicting value twice doesn't hurt - Assert.IsTrue(marktlokation.TryGetExterneReferenz("foo", out actualBar)); - Assert.AreEqual("bar", actualBar); - } + marktlokation.ExterneReferenzen = null; + marktlokation.SetExterneReferenz(new ExterneReferenz + { ExRefName = "foo", ExRefWert = "bar" }); // if null, list is automatically created + marktlokation.SetExterneReferenz(new ExterneReferenz + { ExRefName = "foo", ExRefWert = "bar" }); // setting a non-conflicting value twice doesn't hurt + Assert.IsTrue(marktlokation.TryGetExterneReferenz("foo", out actualBar)); + Assert.AreEqual("bar", actualBar); } } \ No newline at end of file diff --git a/BO4ETestProject/TestGeraetemerkmalConverter.cs b/BO4ETestProject/TestGeraetemerkmalConverter.cs index 0cec9eb7..dfaa912c 100644 --- a/BO4ETestProject/TestGeraetemerkmalConverter.cs +++ b/BO4ETestProject/TestGeraetemerkmalConverter.cs @@ -6,156 +6,155 @@ using Newtonsoft.Json; using JsonException = System.Text.Json.JsonException; -namespace TestBO4E +namespace TestBO4E; + +[TestClass] +public class TestGeraeteerkmalDeserialization { - [TestClass] - public class TestGeraeteerkmalDeserialization + private const string JsonString = "{\"merkmal\":\"G4\"}"; + private const string JsonStringWithPeriod = "{\"merkmal\":\"G2Period5\"}"; + private const string JsonStringWasser = "{\"merkmal\":\"WASSER_MWZW\"}"; + internal class SomethingWithAGeraetemerkmal { - private const string JsonString = "{\"merkmal\":\"G4\"}"; - private const string JsonStringWithPeriod = "{\"merkmal\":\"G2Period5\"}"; - private const string JsonStringWasser = "{\"merkmal\":\"WASSER_MWZW\"}"; - internal class SomethingWithAGeraetemerkmal - { - [JsonProperty(PropertyName = "merkmal")] // system.text - [JsonPropertyName("merkmal")] // newtonsoft - public Geraetemerkmal Merkmal { get; set; } - } + [JsonProperty(PropertyName = "merkmal")] // system.text + [JsonPropertyName("merkmal")] // newtonsoft + public Geraetemerkmal Merkmal { get; set; } + } - internal class SomethingWithANullableGeraetemerkmal - { - [JsonProperty(PropertyName = "merkmal")] // system.text - [JsonPropertyName("merkmal")] // newtonsoft - public Geraetemerkmal? Merkmal { get; set; } - } + internal class SomethingWithANullableGeraetemerkmal + { + [JsonProperty(PropertyName = "merkmal")] // system.text + [JsonPropertyName("merkmal")] // newtonsoft + public Geraetemerkmal? Merkmal { get; set; } + } - [TestMethod] - public void TestNewtonsoft_Error() - { - var errorAction = () => Newtonsoft.Json.JsonConvert.DeserializeObject(JsonString); - errorAction.Should().Throw().Which.Message.StartsWith("Error converting value \"G4\" to type"); - } + [TestMethod] + public void TestNewtonsoft_Error() + { + var errorAction = () => Newtonsoft.Json.JsonConvert.DeserializeObject(JsonString); + errorAction.Should().Throw().Which.Message.StartsWith("Error converting value \"G4\" to type"); + } - [TestMethod] - public void TestSystemText_Error() - { - var errorAction = () => System.Text.Json.JsonSerializer.Deserialize(JsonString); - errorAction.Should().Throw().Which.Message.StartsWith("The JSON value could not be converted to BO4E.ENUM.Geraetemerkmal"); - } + [TestMethod] + public void TestSystemText_Error() + { + var errorAction = () => System.Text.Json.JsonSerializer.Deserialize(JsonString); + errorAction.Should().Throw().Which.Message.StartsWith("The JSON value could not be converted to BO4E.ENUM.Geraetemerkmal"); + } - [TestMethod] - public void TestNewtonsoft_Success_NonNullable() - { - var result = Newtonsoft.Json.JsonConvert.DeserializeObject(JsonString, new LenientGeraetemerkmalGasConverter()); - result.Merkmal.Should().Be(Geraetemerkmal.GAS_G4); - } + [TestMethod] + public void TestNewtonsoft_Success_NonNullable() + { + var result = Newtonsoft.Json.JsonConvert.DeserializeObject(JsonString, new LenientGeraetemerkmalGasConverter()); + result.Merkmal.Should().Be(Geraetemerkmal.GAS_G4); + } - [TestMethod] - public void TestNewtonsoft_Success_NonNullable_GPointSomething() - { - var result = Newtonsoft.Json.JsonConvert.DeserializeObject(JsonStringWithPeriod, new LenientGeraetemerkmalGasConverter()); - result.Merkmal.Should().Be(Geraetemerkmal.GAS_G2P5); - } + [TestMethod] + public void TestNewtonsoft_Success_NonNullable_GPointSomething() + { + var result = Newtonsoft.Json.JsonConvert.DeserializeObject(JsonStringWithPeriod, new LenientGeraetemerkmalGasConverter()); + result.Merkmal.Should().Be(Geraetemerkmal.GAS_G2P5); + } - [TestMethod] - public void TestNewtonsoft_Success_Nullable() - { - var result = Newtonsoft.Json.JsonConvert.DeserializeObject(JsonString, new LenientGeraetemerkmalGasConverter()); - result.Merkmal.Should().Be(Geraetemerkmal.GAS_G4); - } + [TestMethod] + public void TestNewtonsoft_Success_Nullable() + { + var result = Newtonsoft.Json.JsonConvert.DeserializeObject(JsonString, new LenientGeraetemerkmalGasConverter()); + result.Merkmal.Should().Be(Geraetemerkmal.GAS_G4); + } - [TestMethod] - public void TestNewtonsoft_Success_Nullable_WASSER_MWZW() - { - var result = Newtonsoft.Json.JsonConvert.DeserializeObject(JsonString, new LenientGeraetemerkmalGasConverter()); - result.Merkmal.Should().Be(Geraetemerkmal.GAS_G4); - } + [TestMethod] + public void TestNewtonsoft_Success_Nullable_WASSER_MWZW() + { + var result = Newtonsoft.Json.JsonConvert.DeserializeObject(JsonString, new LenientGeraetemerkmalGasConverter()); + result.Merkmal.Should().Be(Geraetemerkmal.GAS_G4); + } - [TestMethod] - public void TestNewtonsoft_Success_Nullable_GPointSomething() - { - var result = Newtonsoft.Json.JsonConvert.DeserializeObject(JsonStringWasser, new LenientGeraetemerkmalGasConverter()); - result.Merkmal.Should().Be(Geraetemerkmal.WASSER_MWZW); - } + [TestMethod] + public void TestNewtonsoft_Success_Nullable_GPointSomething() + { + var result = Newtonsoft.Json.JsonConvert.DeserializeObject(JsonStringWasser, new LenientGeraetemerkmalGasConverter()); + result.Merkmal.Should().Be(Geraetemerkmal.WASSER_MWZW); + } - [TestMethod] - public void TestSystemText_Success_NonNullable() + [TestMethod] + public void TestSystemText_Success_NonNullable() + { + var settings = new System.Text.Json.JsonSerializerOptions() { - var settings = new System.Text.Json.JsonSerializerOptions() - { - Converters = { new LenientSystemTextGeraetemerkmalGasConverter() } - }; - var result = System.Text.Json.JsonSerializer.Deserialize(JsonString, settings); - result.Merkmal.Should().Be(Geraetemerkmal.GAS_G4); - } - - [TestMethod] - public void TestSystemText_Success_NonNullable_WASSER_MWZW() + Converters = { new LenientSystemTextGeraetemerkmalGasConverter() } + }; + var result = System.Text.Json.JsonSerializer.Deserialize(JsonString, settings); + result.Merkmal.Should().Be(Geraetemerkmal.GAS_G4); + } + + [TestMethod] + public void TestSystemText_Success_NonNullable_WASSER_MWZW() + { + var settings = new System.Text.Json.JsonSerializerOptions() { - var settings = new System.Text.Json.JsonSerializerOptions() - { - Converters = { new LenientSystemTextGeraetemerkmalGasConverter() } - }; - var result = System.Text.Json.JsonSerializer.Deserialize(JsonStringWasser, settings); - result.Merkmal.Should().Be(Geraetemerkmal.WASSER_MWZW); - } - - [TestMethod] - public void TestSystemText_Success_GPointSomething() + Converters = { new LenientSystemTextGeraetemerkmalGasConverter() } + }; + var result = System.Text.Json.JsonSerializer.Deserialize(JsonStringWasser, settings); + result.Merkmal.Should().Be(Geraetemerkmal.WASSER_MWZW); + } + + [TestMethod] + public void TestSystemText_Success_GPointSomething() + { + var settings = new System.Text.Json.JsonSerializerOptions() { - var settings = new System.Text.Json.JsonSerializerOptions() - { - Converters = { new LenientSystemTextGeraetemerkmalGasConverter() } - }; - var result = System.Text.Json.JsonSerializer.Deserialize(JsonStringWithPeriod, settings); - result.Merkmal.Should().Be(Geraetemerkmal.GAS_G2P5); - } - - [TestMethod] - public void TestSystemText_Nullable_Success_GPointSomething() + Converters = { new LenientSystemTextGeraetemerkmalGasConverter() } + }; + var result = System.Text.Json.JsonSerializer.Deserialize(JsonStringWithPeriod, settings); + result.Merkmal.Should().Be(Geraetemerkmal.GAS_G2P5); + } + + [TestMethod] + public void TestSystemText_Nullable_Success_GPointSomething() + { + var settings = new System.Text.Json.JsonSerializerOptions() { - var settings = new System.Text.Json.JsonSerializerOptions() - { - Converters = { new LenientSystemTextNullableGeraetemerkmalGasConverter() } - }; - var result = System.Text.Json.JsonSerializer.Deserialize(JsonStringWithPeriod, settings); - result.Merkmal.Should().Be(Geraetemerkmal.GAS_G2P5); - } + Converters = { new LenientSystemTextNullableGeraetemerkmalGasConverter() } + }; + var result = System.Text.Json.JsonSerializer.Deserialize(JsonStringWithPeriod, settings); + result.Merkmal.Should().Be(Geraetemerkmal.GAS_G2P5); + } - [TestMethod] - public void TestSystemText_Write_NonNullable() + [TestMethod] + public void TestSystemText_Write_NonNullable() + { + var settings = new System.Text.Json.JsonSerializerOptions() { - var settings = new System.Text.Json.JsonSerializerOptions() - { - Converters = { new LenientSystemTextGeraetemerkmalGasConverter() } - }; - var instance = new SomethingWithAGeraetemerkmal { Merkmal = Geraetemerkmal.GAS_G4 }; - var json = System.Text.Json.JsonSerializer.Serialize(instance, settings); - json.Should().Be("{\"merkmal\":\"G4\"}"); - } - - [TestMethod] - public void TestSystemText_Write_Nullable() + Converters = { new LenientSystemTextGeraetemerkmalGasConverter() } + }; + var instance = new SomethingWithAGeraetemerkmal { Merkmal = Geraetemerkmal.GAS_G4 }; + var json = System.Text.Json.JsonSerializer.Serialize(instance, settings); + json.Should().Be("{\"merkmal\":\"G4\"}"); + } + + [TestMethod] + public void TestSystemText_Write_Nullable() + { + var settings = new System.Text.Json.JsonSerializerOptions() { - var settings = new System.Text.Json.JsonSerializerOptions() - { - Converters = { new LenientSystemTextNullableGeraetemerkmalGasConverter() } - }; - var instance = new SomethingWithANullableGeraetemerkmal { Merkmal = Geraetemerkmal.GAS_G2P5 }; - var json = System.Text.Json.JsonSerializer.Serialize(instance, settings); - json.Should().Be("{\"merkmal\":\"G2P5\"}"); - } - - [TestMethod] - public void TestSystemText_Write_Nullable_Null() + Converters = { new LenientSystemTextNullableGeraetemerkmalGasConverter() } + }; + var instance = new SomethingWithANullableGeraetemerkmal { Merkmal = Geraetemerkmal.GAS_G2P5 }; + var json = System.Text.Json.JsonSerializer.Serialize(instance, settings); + json.Should().Be("{\"merkmal\":\"G2P5\"}"); + } + + [TestMethod] + public void TestSystemText_Write_Nullable_Null() + { + var settings = new System.Text.Json.JsonSerializerOptions() { - var settings = new System.Text.Json.JsonSerializerOptions() - { - Converters = { new LenientSystemTextNullableGeraetemerkmalGasConverter() } - }; - var instance = new SomethingWithANullableGeraetemerkmal { Merkmal = null }; - var json = System.Text.Json.JsonSerializer.Serialize(instance, settings); - json.Should().Be("{\"merkmal\":null}"); - } - } -} + Converters = { new LenientSystemTextNullableGeraetemerkmalGasConverter() } + }; + var instance = new SomethingWithANullableGeraetemerkmal { Merkmal = null }; + var json = System.Text.Json.JsonSerializer.Serialize(instance, settings); + json.Should().Be("{\"merkmal\":null}"); + } +} \ No newline at end of file diff --git a/BO4ETestProject/TestJsonOrder.cs b/BO4ETestProject/TestJsonOrder.cs index 45ab713b..69cee45e 100644 --- a/BO4ETestProject/TestJsonOrder.cs +++ b/BO4ETestProject/TestJsonOrder.cs @@ -15,153 +15,152 @@ using JsonIgnoreAttribute = System.Text.Json.Serialization.JsonIgnoreAttribute; -namespace TestBO4E +namespace TestBO4E; + +[TestClass] +public class TestJsonOrder { - [TestClass] - public class TestJsonOrder + [TestMethod] + public void TestJsonOrderAttributesOfCOM() { - [TestMethod] - public void TestJsonOrderAttributesOfCOM() - { - TestOrderFromAbstract(typeof(COM)); - } + TestOrderFromAbstract(typeof(COM)); + } - [TestMethod] - public void TestJsonOrderAttributesOfBO() + [TestMethod] + public void TestJsonOrderAttributesOfBO() + { + TestOrderFromAbstract(typeof(BusinessObject)); + } + + /// + /// contains those types where the order of the json elements/properties should _not_ be enforced for now + /// + static readonly HashSet IgnoreOrderTypes = new() + { + // todo: make this list smaller, step by step. + // we could for example assign these as "Strafarbeiten" for commits on dev/main that broke the tests + + // DON'T ADD NEW ENTRIES TO THE LIST + + // BusinessObjects + typeof(Auftrag), + typeof(AuftragsStorno), + typeof(Avis), + typeof(Benachrichtigung), + typeof(Berechnungsformel), + typeof(Energiemenge), + typeof(Entsperrauftrag), + typeof(Marktteilnehmer), + typeof(Kosten), + typeof(PreisblattDienstleistung), + typeof(PreisblattKonzessionsabgabe), + typeof(PreisblattMessung), + typeof(PreisblattNetznutzung), + typeof(PreisblattUmlagen), + typeof(Region), + typeof(Sperrauftrag), + typeof(SperrauftragsStorno), + + // COMponents + typeof(Abweichung), + typeof(AufAbschlag), + typeof(Aufgabe), + typeof(Ausschreibungsdetail), + typeof(Ausschreibungslos), + typeof(Avisposition), + typeof(Betrag), + typeof(COM), + typeof(Dienstleistung), + typeof(Energieherkunft), + typeof(Energiemix), + typeof(ExterneReferenz), + typeof(Fehler), + typeof(FehlerUrsache), + typeof(GenericStringStringInfo), + typeof(Geokoordinaten), + typeof(Handelsunstimmigkeitsbegruendung), + typeof(Hardware), + typeof(Katasteradresse), + typeof(Konzessionsabgabe), + typeof(Kostenblock), + typeof(Kostenposition), + typeof(KriteriumsWert), + typeof(Lastprofil), + //#pragma warning disable CS0619 + // typeof(BO4E.COM.Marktrolle), + //#pragma warning disable CS0619 + typeof(MarktpartnerDetails), + typeof(Messlokationszuordnung), + typeof(Notiz), + typeof(PhysikalischerWert), + typeof(PositionsAufAbschlag), + typeof(Preis), + typeof(Preisgarantie), + typeof(Preisstaffel), + typeof(Rechenschritt), + typeof(RechnungspositionFlat), + typeof(RegionaleGueltigkeit), + typeof(RegionalePreisgarantie), + typeof(RegionalePreisstaffel), + typeof(RegionalerAufAbschlag), + typeof(RegionaleTarifpreisposition), + typeof(Regionskriterium), + typeof(Rufnummer), + typeof(Sigmoidparameter), + typeof(StatusZusatzInformation), + typeof(Steuerbetrag), + typeof(Tagesparameter), + typeof(Tarifberechnungsparameter), + typeof(Tarifeinschraenkung), + typeof(Tarifpreisposition), + typeof(Unterschrift), + typeof(Verbrauch), + typeof(Verwendungszweck), + typeof(Vertragsteil), + typeof(Konfigurationsprodukt), + typeof(Zeitraum), + typeof(Zustaendigkeit) + }; + + protected static void TestOrderFromAbstract(Type abstractBaseType) + { + if (!abstractBaseType.IsAbstract) { - TestOrderFromAbstract(typeof(BusinessObject)); + throw new ArgumentException($"The type {abstractBaseType} is not abstract", nameof(abstractBaseType)); } - /// - /// contains those types where the order of the json elements/properties should _not_ be enforced for now - /// - static readonly HashSet IgnoreOrderTypes = new() - { - // todo: make this list smaller, step by step. - // we could for example assign these as "Strafarbeiten" for commits on dev/main that broke the tests - - // DON'T ADD NEW ENTRIES TO THE LIST - - // BusinessObjects - typeof(Auftrag), - typeof(AuftragsStorno), - typeof(Avis), - typeof(Benachrichtigung), - typeof(Berechnungsformel), - typeof(Energiemenge), - typeof(Entsperrauftrag), - typeof(Marktteilnehmer), - typeof(Kosten), - typeof(PreisblattDienstleistung), - typeof(PreisblattKonzessionsabgabe), - typeof(PreisblattMessung), - typeof(PreisblattNetznutzung), - typeof(PreisblattUmlagen), - typeof(Region), - typeof(Sperrauftrag), - typeof(SperrauftragsStorno), - - // COMponents - typeof(Abweichung), - typeof(AufAbschlag), - typeof(Aufgabe), - typeof(Ausschreibungsdetail), - typeof(Ausschreibungslos), - typeof(Avisposition), - typeof(Betrag), - typeof(COM), - typeof(Dienstleistung), - typeof(Energieherkunft), - typeof(Energiemix), - typeof(ExterneReferenz), - typeof(Fehler), - typeof(FehlerUrsache), - typeof(GenericStringStringInfo), - typeof(Geokoordinaten), - typeof(Handelsunstimmigkeitsbegruendung), - typeof(Hardware), - typeof(Katasteradresse), - typeof(Konzessionsabgabe), - typeof(Kostenblock), - typeof(Kostenposition), - typeof(KriteriumsWert), - typeof(Lastprofil), - //#pragma warning disable CS0619 - // typeof(BO4E.COM.Marktrolle), - //#pragma warning disable CS0619 - typeof(MarktpartnerDetails), - typeof(Messlokationszuordnung), - typeof(Notiz), - typeof(PhysikalischerWert), - typeof(PositionsAufAbschlag), - typeof(Preis), - typeof(Preisgarantie), - typeof(Preisstaffel), - typeof(Rechenschritt), - typeof(RechnungspositionFlat), - typeof(RegionaleGueltigkeit), - typeof(RegionalePreisgarantie), - typeof(RegionalePreisstaffel), - typeof(RegionalerAufAbschlag), - typeof(RegionaleTarifpreisposition), - typeof(Regionskriterium), - typeof(Rufnummer), - typeof(Sigmoidparameter), - typeof(StatusZusatzInformation), - typeof(Steuerbetrag), - typeof(Tagesparameter), - typeof(Tarifberechnungsparameter), - typeof(Tarifeinschraenkung), - typeof(Tarifpreisposition), - typeof(Unterschrift), - typeof(Verbrauch), - typeof(Verwendungszweck), - typeof(Vertragsteil), - typeof(Konfigurationsprodukt), - typeof(Zeitraum), - typeof(Zustaendigkeit) - }; - - protected static void TestOrderFromAbstract(Type abstractBaseType) + var relevantTypes = typeof(BusinessObject).Assembly.GetTypes().Where(abstractBaseType.IsAssignableFrom); + foreach (var relevantType in relevantTypes.Where(t => !IgnoreOrderTypes.Contains(t) && !t.Name.Contains("Marktrolle"))) { - if (!abstractBaseType.IsAbstract) + var properties = relevantType.GetProperties(); + var orders = new HashSet(); + foreach (var dtProperty in properties) { - throw new ArgumentException($"The type {abstractBaseType} is not abstract", nameof(abstractBaseType)); - } + var systemTextIgnore = dtProperty.GetCustomAttributes().FirstOrDefault(); + if (systemTextIgnore is not null) + { + continue; + } - var relevantTypes = typeof(BusinessObject).Assembly.GetTypes().Where(abstractBaseType.IsAssignableFrom); - foreach (var relevantType in relevantTypes.Where(t => !IgnoreOrderTypes.Contains(t) && !t.Name.Contains("Marktrolle"))) - { - var properties = relevantType.GetProperties(); - var orders = new HashSet(); - foreach (var dtProperty in properties) + var systemTextJsonOrderAttribute = dtProperty.GetCustomAttributes().FirstOrDefault(); + systemTextJsonOrderAttribute.Should() + .NotBeNull(because: $"The property {dtProperty.Name} of {relevantType.Name} should have System.Text.JsonPropertyOrderAttribute"); + var newtonSoftJsonPropertyAttribute = dtProperty.GetCustomAttributes().FirstOrDefault(); + newtonSoftJsonPropertyAttribute.Should().NotBeNull($"The property {dtProperty.Name} of {relevantType.Name} should have Newtonsoft.Json.JsonPropertyAttribute"); + var systemTextOrder = systemTextJsonOrderAttribute.Order; + orders.Should().NotContain(systemTextOrder, + because: $"The JsonPropertyOrderAttribute should be unique for {relevantType} but found multiple occurrences of {systemTextOrder}"); + orders.Add(systemTextOrder); + + var newtonsoftIgnore = dtProperty.GetCustomAttributes().FirstOrDefault(); + if (newtonsoftIgnore is not null) { - var systemTextIgnore = dtProperty.GetCustomAttributes().FirstOrDefault(); - if (systemTextIgnore is not null) - { - continue; - } - - var systemTextJsonOrderAttribute = dtProperty.GetCustomAttributes().FirstOrDefault(); - systemTextJsonOrderAttribute.Should() - .NotBeNull(because: $"The property {dtProperty.Name} of {relevantType.Name} should have System.Text.JsonPropertyOrderAttribute"); - var newtonSoftJsonPropertyAttribute = dtProperty.GetCustomAttributes().FirstOrDefault(); - newtonSoftJsonPropertyAttribute.Should().NotBeNull($"The property {dtProperty.Name} of {relevantType.Name} should have Newtonsoft.Json.JsonPropertyAttribute"); - var systemTextOrder = systemTextJsonOrderAttribute.Order; - orders.Should().NotContain(systemTextOrder, - because: $"The JsonPropertyOrderAttribute should be unique for {relevantType} but found multiple occurrences of {systemTextOrder}"); - orders.Add(systemTextOrder); - - var newtonsoftIgnore = dtProperty.GetCustomAttributes().FirstOrDefault(); - if (newtonsoftIgnore is not null) - { - continue; - } - - var newtonsoftOrder = newtonSoftJsonPropertyAttribute.Order; - systemTextOrder.Should().Be(newtonsoftOrder, because: $"System.Text Order and Newtonsoft Order of {relevantType.Name}.{dtProperty.Name} should be the same."); + continue; } + + var newtonsoftOrder = newtonSoftJsonPropertyAttribute.Order; + systemTextOrder.Should().Be(newtonsoftOrder, because: $"System.Text Order and Newtonsoft Order of {relevantType.Name}.{dtProperty.Name} should be the same."); } } } -} +} \ No newline at end of file diff --git a/BO4ETestProject/TestJsonSchemaGeneration.cs b/BO4ETestProject/TestJsonSchemaGeneration.cs index eacbb50a..d1b89c31 100644 --- a/BO4ETestProject/TestJsonSchemaGeneration.cs +++ b/BO4ETestProject/TestJsonSchemaGeneration.cs @@ -5,61 +5,60 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json.Schema; -namespace TestBO4E +namespace TestBO4E; + +[TestClass] +public class TestJsonSchemaGeneration { - [TestClass] - public class TestJsonSchemaGeneration + [TestMethod] + public void BasicTest() { - [TestMethod] - public void BasicTest() - { - var melo = new Messlokation(); - var result = melo.GetJsonScheme().ToString(); + var melo = new Messlokation(); + var result = melo.GetJsonScheme().ToString(); - var em = new Energiemenge(); - result = em.GetJsonScheme().ToString(); + var em = new Energiemenge(); + result = em.GetJsonScheme().ToString(); - var result2 = BusinessObject.GetJsonSchema(typeof(Energiemenge)).ToString(); - Assert.AreEqual(result, result2); - } + var result2 = BusinessObject.GetJsonSchema(typeof(Energiemenge)).ToString(); + Assert.AreEqual(result, result2); + } - [TestMethod] - public void NegativeTest() - { - Assert.ThrowsException(() => BusinessObject.GetJsonSchema(typeof(string)), - "Illegal types must result in a ArgumentException."); - } + [TestMethod] + public void NegativeTest() + { + Assert.ThrowsException(() => BusinessObject.GetJsonSchema(typeof(string)), + "Illegal types must result in a ArgumentException."); + } - private const int LastDataRowOffset = 50; - private const int MaxSchemasPerHour = 10; - [TestMethod] - [DataRow(0)] - [DataRow(10)] - [DataRow(20)] - [DataRow(30)] - [DataRow(40)] - [DataRow(LastDataRowOffset)] // using these different data rows allows you to workaround the 10schema per hour limitation (MaxSchemasPerHour) + private const int LastDataRowOffset = 50; + private const int MaxSchemasPerHour = 10; + [TestMethod] + [DataRow(0)] + [DataRow(10)] + [DataRow(20)] + [DataRow(30)] + [DataRow(40)] + [DataRow(LastDataRowOffset)] // using these different data rows allows you to workaround the 10schema per hour limitation (MaxSchemasPerHour) - public void TestJSchemaFileGenerationBo(int offset) + public void TestJSchemaFileGenerationBo(int offset) + { + var relevantBusinessObjectTypes = typeof(BusinessObject).Assembly.GetTypes() + .Where(t => t.IsSubclassOf(typeof(BusinessObject))); + relevantBusinessObjectTypes.Count().Should().BeLessThan(LastDataRowOffset + MaxSchemasPerHour); // if this fails, add another data row to this test method + try // generate plain json schemas { - var relevantBusinessObjectTypes = typeof(BusinessObject).Assembly.GetTypes() - .Where(t => t.IsSubclassOf(typeof(BusinessObject))); - relevantBusinessObjectTypes.Count().Should().BeLessThan(LastDataRowOffset + MaxSchemasPerHour); // if this fails, add another data row to this test method - try // generate plain json schemas - { - foreach (var type in relevantBusinessObjectTypes.Skip(offset).Take(MaxSchemasPerHour)) - { - var schema = BusinessObject.GetJsonSchema(type); - Assert.IsNotNull(schema); - // writing the schemas has moved to the SchemaGenerator project/generate-json-schemas.sh - } - } - catch (JSchemaException jse) + foreach (var type in relevantBusinessObjectTypes.Skip(offset).Take(MaxSchemasPerHour)) { - Console.Out.WriteLine(jse.Message); - // thats life. pay for it if you'd like to :P + var schema = BusinessObject.GetJsonSchema(type); + Assert.IsNotNull(schema); + // writing the schemas has moved to the SchemaGenerator project/generate-json-schemas.sh } } + catch (JSchemaException jse) + { + Console.Out.WriteLine(jse.Message); + // thats life. pay for it if you'd like to :P + } } -} +} \ No newline at end of file diff --git a/BO4ETestProject/TestMaLoMeLoId.cs b/BO4ETestProject/TestMaLoMeLoId.cs index 09ceb9ef..57933271 100644 --- a/BO4ETestProject/TestMaLoMeLoId.cs +++ b/BO4ETestProject/TestMaLoMeLoId.cs @@ -2,62 +2,61 @@ using BO4E.ENUM; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace TestBO4E +namespace TestBO4E; + +[TestClass] +public class TestMaLoMeLoId { - [TestClass] - public class TestMaLoMeLoId + [TestMethod] + public void TestMeLoIdValidity() { - [TestMethod] - public void TestMeLoIdValidity() - { - Assert.IsFalse(Messlokation.ValidateId(null)); - Assert.IsFalse(Messlokation.ValidateId(" ")); - Assert.IsTrue(Messlokation.ValidateId("DE1234567890123456789012345678901")); - Assert.IsTrue(Messlokation.ValidateId("DE00056266802AO6G56M11SN51G21M24S")); - Assert.IsFalse(Messlokation.ValidateId("deimudderihrfalschemeldoid")); - Assert.IsFalse(Messlokation.ValidateId("kleinbuchstabensindnichterlaubt01")); - } + Assert.IsFalse(Messlokation.ValidateId(null)); + Assert.IsFalse(Messlokation.ValidateId(" ")); + Assert.IsTrue(Messlokation.ValidateId("DE1234567890123456789012345678901")); + Assert.IsTrue(Messlokation.ValidateId("DE00056266802AO6G56M11SN51G21M24S")); + Assert.IsFalse(Messlokation.ValidateId("deimudderihrfalschemeldoid")); + Assert.IsFalse(Messlokation.ValidateId("kleinbuchstabensindnichterlaubt01")); + } - [TestMethod] - public void TestMaLoIdValidity() - { - Assert.IsFalse(Marktlokation.ValidateId(null)); - Assert.IsFalse(Marktlokation.ValidateId(" ")); - Assert.IsTrue(Marktlokation.ValidateId("51238696781")); - Assert.IsTrue(Marktlokation.ValidateId("41373559241")); - Assert.IsTrue(Marktlokation.ValidateId("56789012345")); - Assert.IsTrue(Marktlokation.ValidateId("52935155442")); - Assert.IsFalse(Marktlokation.ValidateId("512386967890")); - Assert.IsFalse(Marktlokation.ValidateId("41373559240")); - Assert.IsFalse(Marktlokation.ValidateId("12345")); - Assert.IsFalse(Marktlokation.ValidateId("asdFG")); - Assert.IsFalse(Marktlokation.ValidateId("DE1234567890123456789012345678901")); - } + [TestMethod] + public void TestMaLoIdValidity() + { + Assert.IsFalse(Marktlokation.ValidateId(null)); + Assert.IsFalse(Marktlokation.ValidateId(" ")); + Assert.IsTrue(Marktlokation.ValidateId("51238696781")); + Assert.IsTrue(Marktlokation.ValidateId("41373559241")); + Assert.IsTrue(Marktlokation.ValidateId("56789012345")); + Assert.IsTrue(Marktlokation.ValidateId("52935155442")); + Assert.IsFalse(Marktlokation.ValidateId("512386967890")); + Assert.IsFalse(Marktlokation.ValidateId("41373559240")); + Assert.IsFalse(Marktlokation.ValidateId("12345")); + Assert.IsFalse(Marktlokation.ValidateId("asdFG")); + Assert.IsFalse(Marktlokation.ValidateId("DE1234567890123456789012345678901")); + } - [TestMethod] - public void TestMaLoValidity() + [TestMethod] + public void TestMaLoValidity() + { + var malo = new Marktlokation { - var malo = new Marktlokation - { - MarktlokationsId = "1235678901", - Sparte = Sparte.STROM, - Energierichtung = Energierichtung.AUSSP, - Regelzone = null - }; - Assert.IsFalse(malo.IsValid()); // because the obligatory bilanzierungsmethode is not set - malo.Bilanzierungsmethode = Bilanzierungsmethode.SLP; - Assert.IsTrue(malo.IsValid(false)); // because all obligatory fields are set - Assert.IsFalse(malo.IsValid()); // but the marklokationsId is wrong - malo.MarktlokationsId = "51238696781"; // matches the appropriate regex and has the right check sum - Assert.IsTrue(malo.IsValid()); - malo.Regelzone = "invalid bullshit"; - Assert.IsFalse(malo.IsValid()); - malo.Regelzone = "10YDE-EON------1"; - Assert.IsTrue(malo.IsValid()); - malo.Bilanzierungsgebiet = "foo bar"; - Assert.IsFalse(malo.IsValid()); - malo.Bilanzierungsgebiet = "11YN10000762-01E"; - Assert.IsTrue(malo.IsValid()); - } + MarktlokationsId = "1235678901", + Sparte = Sparte.STROM, + Energierichtung = Energierichtung.AUSSP, + Regelzone = null + }; + Assert.IsFalse(malo.IsValid()); // because the obligatory bilanzierungsmethode is not set + malo.Bilanzierungsmethode = Bilanzierungsmethode.SLP; + Assert.IsTrue(malo.IsValid(false)); // because all obligatory fields are set + Assert.IsFalse(malo.IsValid()); // but the marklokationsId is wrong + malo.MarktlokationsId = "51238696781"; // matches the appropriate regex and has the right check sum + Assert.IsTrue(malo.IsValid()); + malo.Regelzone = "invalid bullshit"; + Assert.IsFalse(malo.IsValid()); + malo.Regelzone = "10YDE-EON------1"; + Assert.IsTrue(malo.IsValid()); + malo.Bilanzierungsgebiet = "foo bar"; + Assert.IsFalse(malo.IsValid()); + malo.Bilanzierungsgebiet = "11YN10000762-01E"; + Assert.IsTrue(malo.IsValid()); } } \ No newline at end of file diff --git a/BO4ETestProject/TestMultiLangJson.cs b/BO4ETestProject/TestMultiLangJson.cs index 64a81e52..7a68675d 100644 --- a/BO4ETestProject/TestMultiLangJson.cs +++ b/BO4ETestProject/TestMultiLangJson.cs @@ -5,133 +5,132 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json; -namespace TestBO4E +namespace TestBO4E; + +[TestClass] +public class TestMultiLangJson { - [TestClass] - public class TestMultiLangJson + [TestMethod] + public void TestContractResolverSerialization() { - [TestMethod] - public void TestContractResolverSerialization() + var mlb = new MultiLangBo { - var mlb = new MultiLangBo - { - DatumDeutsch = new DateTimeOffset(2018, 1, 1, 0, 0, 0, TimeSpan.Zero), - WertDeutsch = "Hallo Welt" - }; - var settings = new JsonSerializerSettings - { - ContractResolver = new MultiLangResolver(Language.EN), - Formatting = Formatting.Indented - }; - var json = JsonConvert.SerializeObject(mlb, settings); - - Assert.IsTrue(json.Contains("date_english")); - Assert.IsTrue(json.Contains("value_english")); - Assert.IsFalse(json.Contains("datum_deutsch")); - Assert.IsFalse(json.Contains("wert_deutsch")); - - var dEjson = JsonConvert.SerializeObject(mlb); - Assert.IsFalse(dEjson.Contains("date_english")); - Assert.IsFalse(dEjson.Contains("value_english")); - Assert.IsTrue(dEjson.Contains(nameof(MultiLangBo.DatumDeutsch))); - Assert.IsTrue(dEjson.Contains(nameof(MultiLangBo.WertDeutsch))); - } - - [TestMethod] - public void TestNestedContractResolverSerialization() + DatumDeutsch = new DateTimeOffset(2018, 1, 1, 0, 0, 0, TimeSpan.Zero), + WertDeutsch = "Hallo Welt" + }; + var settings = new JsonSerializerSettings { - var mlb = new MultiLangBo + ContractResolver = new MultiLangResolver(Language.EN), + Formatting = Formatting.Indented + }; + var json = JsonConvert.SerializeObject(mlb, settings); + + Assert.IsTrue(json.Contains("date_english")); + Assert.IsTrue(json.Contains("value_english")); + Assert.IsFalse(json.Contains("datum_deutsch")); + Assert.IsFalse(json.Contains("wert_deutsch")); + + var dEjson = JsonConvert.SerializeObject(mlb); + Assert.IsFalse(dEjson.Contains("date_english")); + Assert.IsFalse(dEjson.Contains("value_english")); + Assert.IsTrue(dEjson.Contains(nameof(MultiLangBo.DatumDeutsch))); + Assert.IsTrue(dEjson.Contains(nameof(MultiLangBo.WertDeutsch))); + } + + [TestMethod] + public void TestNestedContractResolverSerialization() + { + var mlb = new MultiLangBo + { + DatumDeutsch = new DateTimeOffset(2018, 1, 1, 0, 0, 0, TimeSpan.Zero), + WertDeutsch = "Hallo Welt", + Intern = new NestedObject { - DatumDeutsch = new DateTimeOffset(2018, 1, 1, 0, 0, 0, TimeSpan.Zero), - WertDeutsch = "Hallo Welt", - Intern = new NestedObject - { - BoolDeutsch = true, - InternDeutsch = "Hallo", - IntDeutsch = 33 - }, - InternList = new List - { - new NestedObject {BoolDeutsch = false, IntDeutsch = 10, InternDeutsch = "internalList1"}, - new NestedObject {BoolDeutsch = false, IntDeutsch = 35, InternDeutsch = "internalList2"}, - new NestedObject {BoolDeutsch = true, IntDeutsch = 1200, InternDeutsch = "internalList3"} - } - }; - var settings = new JsonSerializerSettings + BoolDeutsch = true, + InternDeutsch = "Hallo", + IntDeutsch = 33 + }, + InternList = new List { - ContractResolver = new MultiLangResolver(Language.EN), - Formatting = Formatting.Indented - }; - var json = JsonConvert.SerializeObject(mlb, settings); - - Assert.IsTrue(json.Contains("date_english")); - Assert.IsTrue(json.Contains("value_english")); - Assert.IsFalse(json.Contains("datum_deutsch")); - Assert.IsFalse(json.Contains("wert_deutsch")); - Assert.IsTrue(json.Contains("internal Object List")); - Assert.IsTrue(json.Contains("internal_english")); - Assert.IsFalse(json.Contains("intern_deutsch")); - - var deJson = JsonConvert.SerializeObject(mlb); - Assert.IsFalse(deJson.Contains("date_english")); - Assert.IsFalse(deJson.Contains("value_english")); - Assert.IsTrue(deJson.Contains(nameof(MultiLangBo.DatumDeutsch))); - Assert.IsTrue(deJson.Contains(nameof(MultiLangBo.WertDeutsch))); - Assert.IsTrue(deJson.Contains(nameof(MultiLangBo.InternList))); - Assert.IsTrue(deJson.Contains(nameof(NestedObject.InternDeutsch))); - Assert.IsFalse(deJson.Contains("internal_english")); - - var ml = JsonConvert.DeserializeObject(deJson); - Assert.AreNotEqual(DateTime.MinValue, ml.DatumDeutsch.UtcDateTime); - } - - public class NestedObject + new NestedObject {BoolDeutsch = false, IntDeutsch = 10, InternDeutsch = "internalList1"}, + new NestedObject {BoolDeutsch = false, IntDeutsch = 35, InternDeutsch = "internalList2"}, + new NestedObject {BoolDeutsch = true, IntDeutsch = 1200, InternDeutsch = "internalList3"} + } + }; + var settings = new JsonSerializerSettings { - [FieldName("bool_english", Language.EN)] - public bool BoolDeutsch; + ContractResolver = new MultiLangResolver(Language.EN), + Formatting = Formatting.Indented + }; + var json = JsonConvert.SerializeObject(mlb, settings); - [FieldName("int_english", Language.EN)] - public int IntDeutsch; + Assert.IsTrue(json.Contains("date_english")); + Assert.IsTrue(json.Contains("value_english")); + Assert.IsFalse(json.Contains("datum_deutsch")); + Assert.IsFalse(json.Contains("wert_deutsch")); + Assert.IsTrue(json.Contains("internal Object List")); + Assert.IsTrue(json.Contains("internal_english")); + Assert.IsFalse(json.Contains("intern_deutsch")); - [FieldName("internal_english", Language.EN)] - public string InternDeutsch; - } + var deJson = JsonConvert.SerializeObject(mlb); + Assert.IsFalse(deJson.Contains("date_english")); + Assert.IsFalse(deJson.Contains("value_english")); + Assert.IsTrue(deJson.Contains(nameof(MultiLangBo.DatumDeutsch))); + Assert.IsTrue(deJson.Contains(nameof(MultiLangBo.WertDeutsch))); + Assert.IsTrue(deJson.Contains(nameof(MultiLangBo.InternList))); + Assert.IsTrue(deJson.Contains(nameof(NestedObject.InternDeutsch))); + Assert.IsFalse(deJson.Contains("internal_english")); - public class MultiLangBo : BusinessObject - { - [FieldName("date_english", Language.EN)] - public DateTimeOffset DatumDeutsch; - - [FieldName("internal Object", Language.EN)] - public NestedObject Intern; - - [FieldName("internal Object List", Language.EN)] - public List InternList; - - [FieldName("value_english", Language.EN)] - public string WertDeutsch; - } - - //[TestMethod] - //public void TestRechnungFromSapPrintDocument() - //{ - // string[] files = Directory.GetFiles("TariffMediationTests/sapPrintDocuments/", "*.json"); // there is not - // foreach (string file in files) - // { - // JObject sapPrintDocument; - // using (StreamReader r = new StreamReader(file)) - // { - // string jsonString = r.ReadToEnd(); - // sapPrintDocument = JObject.Parse(jsonString); - // } - // Rechnung rechnung = new Rechnung(sapPrintDocument); - // var settings = new JsonSerializerSettings - // { - // ContractResolver = new MultiLangResolver(Language.EN), - // Formatting = Formatting.Indented - // }; - // var json = JsonConvert.SerializeObject(rechnung, settings); - // } - //} + var ml = JsonConvert.DeserializeObject(deJson); + Assert.AreNotEqual(DateTime.MinValue, ml.DatumDeutsch.UtcDateTime); + } + + public class NestedObject + { + [FieldName("bool_english", Language.EN)] + public bool BoolDeutsch; + + [FieldName("int_english", Language.EN)] + public int IntDeutsch; + + [FieldName("internal_english", Language.EN)] + public string InternDeutsch; } + + public class MultiLangBo : BusinessObject + { + [FieldName("date_english", Language.EN)] + public DateTimeOffset DatumDeutsch; + + [FieldName("internal Object", Language.EN)] + public NestedObject Intern; + + [FieldName("internal Object List", Language.EN)] + public List InternList; + + [FieldName("value_english", Language.EN)] + public string WertDeutsch; + } + + //[TestMethod] + //public void TestRechnungFromSapPrintDocument() + //{ + // string[] files = Directory.GetFiles("TariffMediationTests/sapPrintDocuments/", "*.json"); // there is not + // foreach (string file in files) + // { + // JObject sapPrintDocument; + // using (StreamReader r = new StreamReader(file)) + // { + // string jsonString = r.ReadToEnd(); + // sapPrintDocument = JObject.Parse(jsonString); + // } + // Rechnung rechnung = new Rechnung(sapPrintDocument); + // var settings = new JsonSerializerSettings + // { + // ContractResolver = new MultiLangResolver(Language.EN), + // Formatting = Formatting.Indented + // }; + // var json = JsonConvert.SerializeObject(rechnung, settings); + // } + //} } \ No newline at end of file diff --git a/BO4ETestProject/TestNotizDeserialization.cs b/BO4ETestProject/TestNotizDeserialization.cs index 1468b1f6..bb7737b0 100644 --- a/BO4ETestProject/TestNotizDeserialization.cs +++ b/BO4ETestProject/TestNotizDeserialization.cs @@ -3,26 +3,25 @@ using Newtonsoft.Json; using JsonSerializer = System.Text.Json.JsonSerializer; -namespace TestBO4E +namespace TestBO4E; + +[TestClass] +public class TestNotizDeserialization { - [TestClass] - public class TestNotizDeserialization + [TestMethod] + public void TestMinusRemovalNewtonsoft() { - [TestMethod] - public void TestMinusRemovalNewtonsoft() - { - var n = JsonConvert.DeserializeObject( - "{\"klaerfallnummer\":\"468982\",\"autor\":\"Max Mustermann\",\"zeitpunkt\":\"2019-05-24T14:05:00Z\",\"inhalt\":\"hallo. das ist eine notiz mit einem lustigen emoji 🥝\n------------------------------------------------------------------------\",\"tdid\":\"0002\",\"tdname\":\"0000468982\",\"tdobject\":\"EMMA_CASE\"}"); - Assert.AreEqual("hallo. das ist eine notiz mit einem lustigen emoji 🥝", n.Inhalt); - } + var n = JsonConvert.DeserializeObject( + "{\"klaerfallnummer\":\"468982\",\"autor\":\"Max Mustermann\",\"zeitpunkt\":\"2019-05-24T14:05:00Z\",\"inhalt\":\"hallo. das ist eine notiz mit einem lustigen emoji 🥝\n------------------------------------------------------------------------\",\"tdid\":\"0002\",\"tdname\":\"0000468982\",\"tdobject\":\"EMMA_CASE\"}"); + Assert.AreEqual("hallo. das ist eine notiz mit einem lustigen emoji 🥝", n.Inhalt); + } - [TestMethod] - public void TestMinusRemoval() - { - var n = JsonSerializer.Deserialize( - "{\"klaerfallnummer\":\"468982\",\"autor\":\"Max Mustermann\",\"zeitpunkt\":\"2019-05-24T14:05:00Z\",\"inhalt\":\"hallo. das ist eine notiz mit einem lustigen emoji 🥝\\n------------------------------------------------------------------------\",\"tdid\":\"0002\",\"tdname\":\"0000468982\",\"tdobject\":\"EMMA_CASE\"}"); - Assert.IsNotNull(n); - Assert.AreEqual("hallo. das ist eine notiz mit einem lustigen emoji 🥝", n.Inhalt); - } + [TestMethod] + public void TestMinusRemoval() + { + var n = JsonSerializer.Deserialize( + "{\"klaerfallnummer\":\"468982\",\"autor\":\"Max Mustermann\",\"zeitpunkt\":\"2019-05-24T14:05:00Z\",\"inhalt\":\"hallo. das ist eine notiz mit einem lustigen emoji 🥝\\n------------------------------------------------------------------------\",\"tdid\":\"0002\",\"tdname\":\"0000468982\",\"tdobject\":\"EMMA_CASE\"}"); + Assert.IsNotNull(n); + Assert.AreEqual("hallo. das ist eine notiz mit einem lustigen emoji 🥝", n.Inhalt); } } \ No newline at end of file diff --git a/BO4ETestProject/TestNullable.cs b/BO4ETestProject/TestNullable.cs index fc8a30a7..a3f74b19 100644 --- a/BO4ETestProject/TestNullable.cs +++ b/BO4ETestProject/TestNullable.cs @@ -10,53 +10,52 @@ using Newtonsoft.Json; -namespace TestBO4E +namespace TestBO4E; + +[TestClass] +public class TestNullableAttributes { - [TestClass] - public class TestNullableAttributes + [TestMethod] + public void TestNullableAttributesFromCOM() { - [TestMethod] - public void TestNullableAttributesFromCOM() - { - TestNullableAttributesFromAbstract(typeof(COM)); - } + TestNullableAttributesFromAbstract(typeof(COM)); + } - [TestMethod] - public void TestNullableAttributesFromBO() - { - TestNullableAttributesFromAbstract(typeof(BusinessObject)); - } + [TestMethod] + public void TestNullableAttributesFromBO() + { + TestNullableAttributesFromAbstract(typeof(BusinessObject)); + } - private NullabilityInfoContext _nullabilityContext = new(); + private NullabilityInfoContext _nullabilityContext = new(); - protected void TestNullableAttributesFromAbstract(Type abstractBaseType) + protected void TestNullableAttributesFromAbstract(Type abstractBaseType) + { + if (!abstractBaseType.IsAbstract) { - if (!abstractBaseType.IsAbstract) - { - throw new ArgumentException($"The type {abstractBaseType} is not abstract", nameof(abstractBaseType)); - } + throw new ArgumentException($"The type {abstractBaseType} is not abstract", nameof(abstractBaseType)); + } - var relevantTypes = typeof(BusinessObject).Assembly.GetTypes() - .Where(t => abstractBaseType.IsAssignableFrom(t)); - foreach (var relevantType in relevantTypes) + var relevantTypes = typeof(BusinessObject).Assembly.GetTypes() + .Where(t => abstractBaseType.IsAssignableFrom(t)); + foreach (var relevantType in relevantTypes) + { + var properties = relevantType.GetProperties(); + foreach (var dtProperty in properties) { - var properties = relevantType.GetProperties(); - foreach (var dtProperty in properties) - { - var jpA = dtProperty.GetCustomAttributes().FirstOrDefault(); - if (jpA is not null) + var jpA = dtProperty.GetCustomAttributes().FirstOrDefault(); + if (jpA is not null) + { + if (jpA.Required != Required.Always) // all not required fields have to be nullable { - if (jpA.Required != Required.Always) // all not required fields have to be nullable - { - var nullabilityInfo = _nullabilityContext.Create(dtProperty); - nullabilityInfo.ReadState.Should().Be(NullabilityState.Nullable, $"The property {dtProperty.Name} of type {relevantType.Name} has to be nullable"); - } + var nullabilityInfo = _nullabilityContext.Create(dtProperty); + nullabilityInfo.ReadState.Should().Be(NullabilityState.Nullable, $"The property {dtProperty.Name} of type {relevantType.Name} has to be nullable"); } } } } } -} +} \ No newline at end of file diff --git a/BO4ETestProject/TestProtoFileGeneration.cs b/BO4ETestProject/TestProtoFileGeneration.cs index e4092028..27adc7ca 100644 --- a/BO4ETestProject/TestProtoFileGeneration.cs +++ b/BO4ETestProject/TestProtoFileGeneration.cs @@ -6,53 +6,52 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using ProtoBuf; -namespace TestBO4E +namespace TestBO4E; + +[TestClass] +public class TestProtoFileGeneration { - [TestClass] - public class TestProtoFileGeneration + private static readonly IReadOnlyCollection ProtoSerializableTypes = new List + { + typeof(Angebot), + typeof(Ansprechpartner), + typeof(Benachrichtigung), + typeof(Energiemenge), + typeof(Geschaeftspartner), + typeof(Kosten), + typeof(Marktlokation), + //typeof(Marktteilnehmer), + typeof(Messlokation), + typeof(Preisblatt), + typeof(Rechnung), + typeof(Region), + typeof(Vertrag), + typeof(Zaehler) + }; + + [TestMethod] + public void TestProtoGenerationBo() { - private static readonly IReadOnlyCollection ProtoSerializableTypes = new List + var method = typeof(Serializer).GetMethod(nameof(Serializer.GetProto), + new[] { typeof(ProtoBuf.Meta.SchemaGenerationOptions) }); + + Assert.IsNotNull(method); + var options = new ProtoBuf.Meta.SchemaGenerationOptions { - typeof(Angebot), - typeof(Ansprechpartner), - typeof(Benachrichtigung), - typeof(Energiemenge), - typeof(Geschaeftspartner), - typeof(Kosten), - typeof(Marktlokation), - //typeof(Marktteilnehmer), - typeof(Messlokation), - typeof(Preisblatt), - typeof(Rechnung), - typeof(Region), - typeof(Vertrag), - typeof(Zaehler) + Syntax = ProtoBuf.Meta.ProtoSyntax.Proto3, + Flags = ProtoBuf.Meta.SchemaGenerationFlags.MultipleNamespaceSupport, + Package = "bo4e", }; - - [TestMethod] - public void TestProtoGenerationBo() + options.Types.AddRange(ProtoSerializableTypes); + var protoString = (string)method.Invoke(null, new object[] { options }); + Assert.IsFalse(string.IsNullOrWhiteSpace(protoString)); + var path = $"../../../../BO4E/protobuf-files/bo4e.proto"; + if (!File.Exists(path)) { - var method = typeof(Serializer).GetMethod(nameof(Serializer.GetProto), - new[] { typeof(ProtoBuf.Meta.SchemaGenerationOptions) }); - - Assert.IsNotNull(method); - var options = new ProtoBuf.Meta.SchemaGenerationOptions - { - Syntax = ProtoBuf.Meta.ProtoSyntax.Proto3, - Flags = ProtoBuf.Meta.SchemaGenerationFlags.MultipleNamespaceSupport, - Package = "bo4e", - }; - options.Types.AddRange(ProtoSerializableTypes); - var protoString = (string)method.Invoke(null, new object[] { options }); - Assert.IsFalse(string.IsNullOrWhiteSpace(protoString)); - var path = $"../../../../BO4E/protobuf-files/bo4e.proto"; - if (!File.Exists(path)) - { - var stream = File.Create(path); - stream.Close(); - } - - File.WriteAllText(path, protoString, new UTF8Encoding(false)); + var stream = File.Create(path); + stream.Close(); } + + File.WriteAllText(path, protoString, new UTF8Encoding(false)); } } \ No newline at end of file diff --git a/BO4ETestProject/TestProtobufAttributes.cs b/BO4ETestProject/TestProtobufAttributes.cs index dd2c7589..0a81bf82 100644 --- a/BO4ETestProject/TestProtobufAttributes.cs +++ b/BO4ETestProject/TestProtobufAttributes.cs @@ -10,282 +10,281 @@ using Newtonsoft.Json; using ProtoBuf; -namespace TestBO4E +namespace TestBO4E; + +[TestClass] +public class TestProtobufAttributes { - [TestClass] - public class TestProtobufAttributes + [TestMethod] + public void TestProtobufDateTimeWorkaroundCOM() { - [TestMethod] - public void TestProtobufDateTimeWorkaroundCOM() - { - TestProtobufDateTimeWorkaround(typeof(COM)); - } + TestProtobufDateTimeWorkaround(typeof(COM)); + } - [TestMethod] - public void TestUniqueProtobufMemberIdCOM() - { - TestUniqueProtobufMemberIdAbstract(typeof(COM)); - } + [TestMethod] + public void TestUniqueProtobufMemberIdCOM() + { + TestUniqueProtobufMemberIdAbstract(typeof(COM)); + } - [TestMethod] - public void TestUniqueProtoIncludeTagsCOM() - { - TestUniqueProtoIncludeTagAbstract(typeof(COM)); - } + [TestMethod] + public void TestUniqueProtoIncludeTagsCOM() + { + TestUniqueProtoIncludeTagAbstract(typeof(COM)); + } - [TestMethod] - public void TestProtobufDateTimeWorkaroundBO() + [TestMethod] + public void TestProtobufDateTimeWorkaroundBO() + { + TestProtobufDateTimeWorkaround(typeof(BusinessObject)); + } + + [TestMethod] + public void TestUniqueProtobufMemberIdBO() + { + TestUniqueProtobufMemberIdAbstract(typeof(BusinessObject)); + } + + [TestMethod] + public void TestUniqueProtoIncludeTagsBO() + { + TestUniqueProtoIncludeTagAbstract(typeof(BusinessObject)); + } + + protected void TestUniqueProtobufMemberIdAbstract(Type abstractType) + { + if (!abstractType.IsAbstract) { - TestProtobufDateTimeWorkaround(typeof(BusinessObject)); + throw new ArgumentException($"The type {abstractType} is not abstract", nameof(abstractType)); } - [TestMethod] - public void TestUniqueProtobufMemberIdBO() + foreach (var type in + typeof(BusinessObject).Assembly.GetTypes().Where(t => abstractType.IsAssignableFrom(t))) + TestProtobufType(type, type.BaseType == abstractType || type == abstractType); + } + + protected void TestProtobufType(Type type, bool isDirectBase) + { + FieldInfo[] allFields; + IEnumerable fieldsWithProtoMemberAttribute; + if (isDirectBase) { - TestUniqueProtobufMemberIdAbstract(typeof(BusinessObject)); + allFields = type.GetFields(BindingFlags.Public | BindingFlags.Instance); + fieldsWithProtoMemberAttribute = type.GetFields(BindingFlags.Public | BindingFlags.Instance) + .Where(f => f.GetCustomAttributes(typeof(ProtoMemberAttribute), true).Any()); } - - [TestMethod] - public void TestUniqueProtoIncludeTagsBO() + else { - TestUniqueProtoIncludeTagAbstract(typeof(BusinessObject)); + allFields = type.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); + fieldsWithProtoMemberAttribute = type + .GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly).Where(f => + f.GetCustomAttributes(typeof(ProtoMemberAttribute), false).Any()); } - protected void TestUniqueProtobufMemberIdAbstract(Type abstractType) - { - if (!abstractType.IsAbstract) - { - throw new ArgumentException($"The type {abstractType} is not abstract", nameof(abstractType)); - } + var nonOfficialFieldsWithProtoMember = allFields + .Where(field => + field.GetCustomAttributes(typeof(NonOfficialAttribute)) + .Any()) // those fields having an [NonOfficial(...)] attribute + .Where(field => + ((NonOfficialAttribute)field.GetCustomAttributes(typeof(NonOfficialAttribute)).First()) + .HasCategory(NonOfficialCategory.CUSTOMER_REQUIREMENTS)) // and the customer_requirements category + .Intersect(fieldsWithProtoMemberAttribute); // and a [ProtoMember()] attribute - foreach (var type in - typeof(BusinessObject).Assembly.GetTypes().Where(t => abstractType.IsAssignableFrom(t))) - TestProtobufType(type, type.BaseType == abstractType || type == abstractType); - } + var wrongTagsNonOfficial = nonOfficialFieldsWithProtoMember.Where(f => + ((ProtoMemberAttribute)f.GetCustomAttributes(typeof(ProtoMemberAttribute)).First()).Tag < 1000); + Assert.AreEqual(0, wrongTagsNonOfficial.Count(), + $"Fields in {type} are non official and do not have proto tags >= 1000: {string.Join(", ", wrongTagsNonOfficial.Select(f => f.Name))}"); + var wrongTagsOfficial = fieldsWithProtoMemberAttribute.Except(nonOfficialFieldsWithProtoMember).Where(f => + ((ProtoMemberAttribute)f.GetCustomAttributes(typeof(ProtoMemberAttribute)).First()).Tag > 1000); + Assert.AreEqual(0, wrongTagsOfficial.Count(), + $"Fields in {type} are official but have proto tags >= 1000: {string.Join(", ", wrongTagsOfficial.Select(f => f.Name))}"); - protected void TestProtobufType(Type type, bool isDirectBase) + try { - FieldInfo[] allFields; - IEnumerable fieldsWithProtoMemberAttribute; if (isDirectBase) { - allFields = type.GetFields(BindingFlags.Public | BindingFlags.Instance); - fieldsWithProtoMemberAttribute = type.GetFields(BindingFlags.Public | BindingFlags.Instance) - .Where(f => f.GetCustomAttributes(typeof(ProtoMemberAttribute), true).Any()); - } - else - { - allFields = type.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); - fieldsWithProtoMemberAttribute = type - .GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly).Where(f => - f.GetCustomAttributes(typeof(ProtoMemberAttribute), false).Any()); + Assert.AreEqual(allFields.Length, fieldsWithProtoMemberAttribute.Count(), + $"Missing protobuf attributes for {type} for: " + + string.Join(", ", allFields.Except(fieldsWithProtoMemberAttribute))); } + } + catch (ArgumentOutOfRangeException aoore) when (aoore.ParamName == "tag") + { + Assert.IsTrue(false, $"Do you have any ProtoMember attributes with an id<=0 in {type}?"); + throw; + } - var nonOfficialFieldsWithProtoMember = allFields - .Where(field => - field.GetCustomAttributes(typeof(NonOfficialAttribute)) - .Any()) // those fields having an [NonOfficial(...)] attribute - .Where(field => - ((NonOfficialAttribute)field.GetCustomAttributes(typeof(NonOfficialAttribute)).First()) - .HasCategory(NonOfficialCategory.CUSTOMER_REQUIREMENTS)) // and the customer_requirements category - .Intersect(fieldsWithProtoMemberAttribute); // and a [ProtoMember()] attribute - - var wrongTagsNonOfficial = nonOfficialFieldsWithProtoMember.Where(f => - ((ProtoMemberAttribute)f.GetCustomAttributes(typeof(ProtoMemberAttribute)).First()).Tag < 1000); - Assert.AreEqual(0, wrongTagsNonOfficial.Count(), - $"Fields in {type} are non official and do not have proto tags >= 1000: {string.Join(", ", wrongTagsNonOfficial.Select(f => f.Name))}"); - var wrongTagsOfficial = fieldsWithProtoMemberAttribute.Except(nonOfficialFieldsWithProtoMember).Where(f => - ((ProtoMemberAttribute)f.GetCustomAttributes(typeof(ProtoMemberAttribute)).First()).Tag > 1000); - Assert.AreEqual(0, wrongTagsOfficial.Count(), - $"Fields in {type} are official but have proto tags >= 1000: {string.Join(", ", wrongTagsOfficial.Select(f => f.Name))}"); - - try - { - if (isDirectBase) - { - Assert.AreEqual(allFields.Length, fieldsWithProtoMemberAttribute.Count(), - $"Missing protobuf attributes for {type} for: " + - string.Join(", ", allFields.Except(fieldsWithProtoMemberAttribute))); - } - } - catch (ArgumentOutOfRangeException aoore) when (aoore.ParamName == "tag") - { - Assert.IsTrue(false, $"Do you have any ProtoMember attributes with an id<=0 in {type}?"); - throw; - } + if (isDirectBase) // because protobuf-net doesn't support multiple levels of inheritance + { + var duplicateTags = fieldsWithProtoMemberAttribute + .Select(f => f.GetCustomAttributes(typeof(ProtoMemberAttribute), true).First()) + .Cast() + .GroupBy(pma => pma.Tag) + .Where(g => g.Count() > 1) + .ToDictionary(pma => pma.Key, y => y.Count()); + Assert.AreEqual(0, duplicateTags.Count, + $"The following [(ProtoMember()] tags in {type} are not unique: {string.Join(", ", duplicateTags.Keys)}"); + } + else + { + Assert.AreEqual(0, fieldsWithProtoMemberAttribute.Count(), + $"Classes like {type} not directly inheriting from BusinessObject or COM must not have Protobuf Attributes (due to protobuf-net bugs)"); + } + } - if (isDirectBase) // because protobuf-net doesn't support multiple levels of inheritance - { - var duplicateTags = fieldsWithProtoMemberAttribute - .Select(f => f.GetCustomAttributes(typeof(ProtoMemberAttribute), true).First()) - .Cast() - .GroupBy(pma => pma.Tag) - .Where(g => g.Count() > 1) - .ToDictionary(pma => pma.Key, y => y.Count()); - Assert.AreEqual(0, duplicateTags.Count, - $"The following [(ProtoMember()] tags in {type} are not unique: {string.Join(", ", duplicateTags.Keys)}"); - } - else - { - Assert.AreEqual(0, fieldsWithProtoMemberAttribute.Count(), - $"Classes like {type} not directly inheriting from BusinessObject or COM must not have Protobuf Attributes (due to protobuf-net bugs)"); - } + protected void TestProtobufDateTimeWorkaround(Type abstractBaseType) + { + if (!abstractBaseType.IsAbstract) + { + throw new ArgumentException($"The type {abstractBaseType} is not abstract", nameof(abstractBaseType)); } - protected void TestProtobufDateTimeWorkaround(Type abstractBaseType) + var relevantTypes = typeof(BusinessObject).Assembly.GetTypes() + .Where(t => abstractBaseType.IsAssignableFrom(t)); + foreach (var relevantType in relevantTypes) { - if (!abstractBaseType.IsAbstract) + var dtProperties = relevantType.GetProperties().Where(p => + p.PropertyType == typeof(DateTime)); + foreach (var dtProperty in dtProperties) { - throw new ArgumentException($"The type {abstractBaseType} is not abstract", nameof(abstractBaseType)); + // there must be an attribute like described in https://github.com/protobuf-net/protobuf-net.Grpc/issues/56#issuecomment-580509687 + var pma = dtProperty.GetCustomAttributes().FirstOrDefault(); + Assert.IsNotNull(pma, + $"The property {dtProperty.Name} of type {relevantType.Name} is missing the ProtoMemberAttribute."); + var cla = dtProperty.GetCustomAttributes().FirstOrDefault(); + Assert.AreEqual(CompatibilityLevel.Level240, cla?.Level, $"The property {dtProperty.Name} of type {relevantType.Name} does not have the Compatability Level Attribute or the wrong value"); } - var relevantTypes = typeof(BusinessObject).Assembly.GetTypes() - .Where(t => abstractBaseType.IsAssignableFrom(t)); - foreach (var relevantType in relevantTypes) + var nullableDtProperties = relevantType.GetProperties().Where(p => + p.PropertyType == typeof(DateTime?) || p.PropertyType == typeof(DateTimeOffset) || p.PropertyType == typeof(DateTimeOffset?)); + foreach (var nullableDtProperty in nullableDtProperties) { - var dtProperties = relevantType.GetProperties().Where(p => - p.PropertyType == typeof(DateTime)); - foreach (var dtProperty in dtProperties) + // as long as protobuf-net is not able to handle nullable native types this is required. see f.e. https://github.com/protobuf-net/protobuf-net/issues/742 + var pia = nullableDtProperty.GetCustomAttributes().FirstOrDefault(); + if (relevantType == typeof(Zeitraum) && new HashSet { "startzeitpunkt", "endzeitpunkt" }.Contains(nullableDtProperty.Name.ToLower())) { - // there must be an attribute like described in https://github.com/protobuf-net/protobuf-net.Grpc/issues/56#issuecomment-580509687 - var pma = dtProperty.GetCustomAttributes().FirstOrDefault(); - Assert.IsNotNull(pma, - $"The property {dtProperty.Name} of type {relevantType.Name} is missing the ProtoMemberAttribute."); - var cla = dtProperty.GetCustomAttributes().FirstOrDefault(); - Assert.AreEqual(CompatibilityLevel.Level240, cla?.Level, $"The property {dtProperty.Name} of type {relevantType.Name} does not have the Compatability Level Attribute or the wrong value"); - } - - var nullableDtProperties = relevantType.GetProperties().Where(p => - p.PropertyType == typeof(DateTime?) || p.PropertyType == typeof(DateTimeOffset) || p.PropertyType == typeof(DateTimeOffset?)); - foreach (var nullableDtProperty in nullableDtProperties) - { - // as long as protobuf-net is not able to handle nullable native types this is required. see f.e. https://github.com/protobuf-net/protobuf-net/issues/742 - var pia = nullableDtProperty.GetCustomAttributes().FirstOrDefault(); - if (relevantType == typeof(Zeitraum) && new HashSet { "startzeitpunkt", "endzeitpunkt" }.Contains(nullableDtProperty.Name.ToLower())) - { - continue; - } - Assert.IsNotNull(pia, - $"The property {nullableDtProperty.Name} of type {relevantType.Name} is missing the {nameof(ProtoIgnoreAttribute)}."); - Assert.IsTrue(relevantType.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance).Any(p => p.GetCustomAttributes().Any(pma => pma.Name == nullableDtProperty.Name) - && p.GetCustomAttributes().Any() - && p.GetCustomAttributes().Any() - && p.GetCustomAttributes().Any(cla => cla.Level == CompatibilityLevel.Level240)), - $"There is no workaround property for {relevantType.FullName}.{nullableDtProperty.Name} that has a {nameof(ProtoMemberAttribute)} with the same 'Name={nullableDtProperty.Name}' and the expected Compatability Level and JsonIgnore Attributes."); + continue; } + Assert.IsNotNull(pia, + $"The property {nullableDtProperty.Name} of type {relevantType.Name} is missing the {nameof(ProtoIgnoreAttribute)}."); + Assert.IsTrue(relevantType.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance).Any(p => p.GetCustomAttributes().Any(pma => pma.Name == nullableDtProperty.Name) + && p.GetCustomAttributes().Any() + && p.GetCustomAttributes().Any() + && p.GetCustomAttributes().Any(cla => cla.Level == CompatibilityLevel.Level240)), + $"There is no workaround property for {relevantType.FullName}.{nullableDtProperty.Name} that has a {nameof(ProtoMemberAttribute)} with the same 'Name={nullableDtProperty.Name}' and the expected Compatability Level and JsonIgnore Attributes."); } } + } - protected void TestUniqueProtoIncludeTagAbstract(Type abstractBaseType) // ToDo: test this with preisblatt + protected void TestUniqueProtoIncludeTagAbstract(Type abstractBaseType) // ToDo: test this with preisblatt + { + if (!abstractBaseType.IsAbstract) { - if (!abstractBaseType.IsAbstract) - { - throw new ArgumentException($"The type {abstractBaseType} is not abstract", nameof(abstractBaseType)); - } - - var duplicateIncludeTags = typeof(BusinessObject).Assembly.GetTypes() - .Where(t => abstractBaseType.IsAssignableFrom(t)) - .SelectMany(t => t.GetCustomAttributes(typeof(ProtoIncludeAttribute), false)) - .Cast() - .GroupBy(pia => pia.Tag) - .Where(g => g.Count() > 1) - .ToDictionary(pia => pia.Key, tag => tag.Count()); - Assert.AreEqual(0, duplicateIncludeTags.Count, - $"The following [(ProtoInclude(, ...)] attributes are not unique: {string.Join(", ", duplicateIncludeTags.Keys)}"); + throw new ArgumentException($"The type {abstractBaseType} is not abstract", nameof(abstractBaseType)); } - [TestMethod] - public void TestProtoEnumConsistency() //https://github.com/protobuf-net/protobuf-net/issues/60 + var duplicateIncludeTags = typeof(BusinessObject).Assembly.GetTypes() + .Where(t => abstractBaseType.IsAssignableFrom(t)) + .SelectMany(t => t.GetCustomAttributes(typeof(ProtoIncludeAttribute), false)) + .Cast() + .GroupBy(pia => pia.Tag) + .Where(g => g.Count() > 1) + .ToDictionary(pia => pia.Key, tag => tag.Count()); + Assert.AreEqual(0, duplicateIncludeTags.Count, + $"The following [(ProtoInclude(, ...)] attributes are not unique: {string.Join(", ", duplicateIncludeTags.Keys)}"); + } + + [TestMethod] + public void TestProtoEnumConsistency() //https://github.com/protobuf-net/protobuf-net/issues/60 + { + var enumTypes = typeof(AbgabeArt).Assembly.GetTypes() + .Where(t => t.IsEnum && t.Namespace.StartsWith("BO4E.ENUM") && + !t.Namespace.StartsWith("BO4E.ENUM.EDI")); + var allValues = new List>(); + foreach (var enumType in enumTypes) { - var enumTypes = typeof(AbgabeArt).Assembly.GetTypes() - .Where(t => t.IsEnum && t.Namespace.StartsWith("BO4E.ENUM") && - !t.Namespace.StartsWith("BO4E.ENUM.EDI")); - var allValues = new List>(); - foreach (var enumType in enumTypes) + var naturalEnumValues = enumType.GetFields() + .Where(f => !f.GetCustomAttributes().Any()) + .Select(f => new Tuple(enumType, f.Name)); + allValues.AddRange(naturalEnumValues); + //var protoEnumValues = enumType.GetFields().SelectMany(f => f.GetCustomAttributes()).Select(pea => new Tuple(enumType, pea.Name)); + //allValues.AddRange(protoEnumValues); + foreach (var field in enumType.GetFields() + .Where(f => f.GetCustomAttributes().Any())) { - var naturalEnumValues = enumType.GetFields() - .Where(f => !f.GetCustomAttributes().Any()) - .Select(f => new Tuple(enumType, f.Name)); - allValues.AddRange(naturalEnumValues); - //var protoEnumValues = enumType.GetFields().SelectMany(f => f.GetCustomAttributes()).Select(pea => new Tuple(enumType, pea.Name)); - //allValues.AddRange(protoEnumValues); - foreach (var field in enumType.GetFields() - .Where(f => f.GetCustomAttributes().Any())) - { - var pea = field.GetCustomAttributes().First(); - Assert.AreEqual(enumType.Name + "_" + field.Name, pea.Name); - allValues.Add(new Tuple(enumType, pea.Name)); - } - - Assert.IsTrue(Enum.IsDefined(enumType, 0), - $"Any enum must define a ZERO like value for Protobuf3 but {enumType} doesn't."); + var pea = field.GetCustomAttributes().First(); + Assert.AreEqual(enumType.Name + "_" + field.Name, pea.Name); + allValues.Add(new Tuple(enumType, pea.Name)); } - var nonDistinctValues = allValues - .GroupBy(tuple => tuple.Item2) // group by field/protoenum name - .Where(g => g.Count() > 1 && g.Key != "value__") - .ToDictionary(x => x.Key, y => y.Select(t => t.Item1.Name)); - Assert.IsFalse(nonDistinctValues.Any(), - $"There are non-distinct Enum values. Add a matching [ProtoEnum] attribute to: {JsonConvert.SerializeObject(nonDistinctValues)}"); + Assert.IsTrue(Enum.IsDefined(enumType, 0), + $"Any enum must define a ZERO like value for Protobuf3 but {enumType} doesn't."); } - [TestMethod] - public void TestExplicitProtobufInheritance() + var nonDistinctValues = allValues + .GroupBy(tuple => tuple.Item2) // group by field/protoenum name + .Where(g => g.Count() > 1 && g.Key != "value__") + .ToDictionary(x => x.Key, y => y.Select(t => t.Item1.Name)); + Assert.IsFalse(nonDistinctValues.Any(), + $"There are non-distinct Enum values. Add a matching [ProtoEnum] attribute to: {JsonConvert.SerializeObject(nonDistinctValues)}"); + } + + [TestMethod] + public void TestExplicitProtobufInheritance() + { + var businessObjectTypes = typeof(BusinessObject).Assembly.GetTypes() + .Where(t => typeof(BusinessObject).IsAssignableFrom(t)); + var boTypesCrossProduct = + from baseType in businessObjectTypes + from inheritingType in businessObjectTypes + where baseType.IsAssignableFrom(inheritingType) && baseType != inheritingType + select new { baseType, inheritingType }; + // Background: https://github.com/protobuf-net/protobuf-net#inheritance + // The base type must have an attribute that refers to the inherited type. + // Both types need to carry the ProtoContract attribute. + foreach (var typePair in boTypesCrossProduct.Distinct()) { - var businessObjectTypes = typeof(BusinessObject).Assembly.GetTypes() - .Where(t => typeof(BusinessObject).IsAssignableFrom(t)); - var boTypesCrossProduct = - from baseType in businessObjectTypes - from inheritingType in businessObjectTypes - where baseType.IsAssignableFrom(inheritingType) && baseType != inheritingType - select new { baseType, inheritingType }; - // Background: https://github.com/protobuf-net/protobuf-net#inheritance - // The base type must have an attribute that refers to the inherited type. - // Both types need to carry the ProtoContract attribute. - foreach (var typePair in boTypesCrossProduct.Distinct()) + // Assert.IsTrue(typePair.baseType.GetCustomAttributes(typeof(ProtoContractAttribute), false).Any(), $"The (base) type {typePair.baseType} has not [ProtoContract] attribute."); // ToDo: re-add this line because fields on BO / COM level are not properly proto-serialized as of now! + if (typePair.inheritingType.BaseType == + typeof(BusinessObject)) //because protobuf-net doesn't support mutliple levels of inheritance { - // Assert.IsTrue(typePair.baseType.GetCustomAttributes(typeof(ProtoContractAttribute), false).Any(), $"The (base) type {typePair.baseType} has not [ProtoContract] attribute."); // ToDo: re-add this line because fields on BO / COM level are not properly proto-serialized as of now! - if (typePair.inheritingType.BaseType == - typeof(BusinessObject)) //because protobuf-net doesn't support mutliple levels of inheritance - { - Assert.IsTrue( - typePair.inheritingType.GetCustomAttributes(typeof(ProtoContractAttribute), false).Any(), - $"The (inheriting) type {typePair.inheritingType} has not [ProtoContract] attribute."); - } - else - { - Assert.IsFalse( - typePair.inheritingType.GetCustomAttributes(typeof(ProtoContractAttribute), false).Any(), - $"The (INDIRECTLY inheriting) type {typePair.inheritingType} has the [ProtoContract] attribute."); // bug in protobuf-net - } + Assert.IsTrue( + typePair.inheritingType.GetCustomAttributes(typeof(ProtoContractAttribute), false).Any(), + $"The (inheriting) type {typePair.inheritingType} has not [ProtoContract] attribute."); + } + else + { + Assert.IsFalse( + typePair.inheritingType.GetCustomAttributes(typeof(ProtoContractAttribute), false).Any(), + $"The (INDIRECTLY inheriting) type {typePair.inheritingType} has the [ProtoContract] attribute."); // bug in protobuf-net + } - if (typePair.inheritingType.BaseType == typePair.baseType && - typePair.baseType != typeof(BusinessObject)) - { - // remove the if-block around this statement as soon as protobuf-net supports multiple levels of inheritance - // Symptomes: - // 1: ProtoBuf.ProtoException: Type 'BO4E.COM.Preisgarantie' can only participate in one inheritance hierarchy (BO4E.COM.Verbrauch) ---> System.InvalidOperationException: Type 'BO4E.COM.Preisgarantie' can only participate in one inheritance hierarchy - // 2: System.InvalidOperationException: Duplicate field-number detected; - var typesReferencedByBase = typePair.baseType - .GetCustomAttributes(typeof(ProtoIncludeAttribute), false).Cast() - .Select(pia => pia.KnownType); - Assert.IsFalse(typesReferencedByBase.Contains(typePair.inheritingType), - $"The base type {typePair.baseType} does not reference the inheriting type {typePair.inheritingType} in a [ProtoInclude(, {typePair.inheritingType})] attribute."); + if (typePair.inheritingType.BaseType == typePair.baseType && + typePair.baseType != typeof(BusinessObject)) + { + // remove the if-block around this statement as soon as protobuf-net supports multiple levels of inheritance + // Symptomes: + // 1: ProtoBuf.ProtoException: Type 'BO4E.COM.Preisgarantie' can only participate in one inheritance hierarchy (BO4E.COM.Verbrauch) ---> System.InvalidOperationException: Type 'BO4E.COM.Preisgarantie' can only participate in one inheritance hierarchy + // 2: System.InvalidOperationException: Duplicate field-number detected; + var typesReferencedByBase = typePair.baseType + .GetCustomAttributes(typeof(ProtoIncludeAttribute), false).Cast() + .Select(pia => pia.KnownType); + Assert.IsFalse(typesReferencedByBase.Contains(typePair.inheritingType), + $"The base type {typePair.baseType} does not reference the inheriting type {typePair.inheritingType} in a [ProtoInclude(, {typePair.inheritingType})] attribute."); - continue; - } + continue; + } - Assert.IsTrue(typePair.baseType.GetCustomAttributes(typeof(ProtoIncludeAttribute), false).Any(), - $"The base type {typePair.baseType} must refer to the inheriting type {typePair.inheritingType} using a [ProtoInclude] attribute."); - if (typePair.inheritingType.BaseType == typePair.baseType) - { - var typesReferencedByBase = typePair.baseType - .GetCustomAttributes(typeof(ProtoIncludeAttribute), false).Cast() - .Select(pia => pia.KnownType); - Assert.IsTrue(typesReferencedByBase.Contains(typePair.inheritingType), - $"The base type {typePair.baseType} does not reference the inheriting type {typePair.inheritingType} in a [ProtoInclude(, {typePair.inheritingType})] attribute."); - } + Assert.IsTrue(typePair.baseType.GetCustomAttributes(typeof(ProtoIncludeAttribute), false).Any(), + $"The base type {typePair.baseType} must refer to the inheriting type {typePair.inheritingType} using a [ProtoInclude] attribute."); + if (typePair.inheritingType.BaseType == typePair.baseType) + { + var typesReferencedByBase = typePair.baseType + .GetCustomAttributes(typeof(ProtoIncludeAttribute), false).Cast() + .Select(pia => pia.KnownType); + Assert.IsTrue(typesReferencedByBase.Contains(typePair.inheritingType), + $"The base type {typePair.baseType} does not reference the inheriting type {typePair.inheritingType} in a [ProtoInclude(, {typePair.inheritingType})] attribute."); } } } -} +} \ No newline at end of file diff --git a/BO4ETestProject/TestSperrauftrag.cs b/BO4ETestProject/TestSperrauftrag.cs index ab61e1a6..9dfacc87 100644 --- a/BO4ETestProject/TestSperrauftrag.cs +++ b/BO4ETestProject/TestSperrauftrag.cs @@ -8,120 +8,119 @@ using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace TestBO4E +namespace TestBO4E; + +/// +/// This is a class to create MWE (Ent)sperraufträge +/// +[TestClass] +public class TestSperrauftrag { - /// - /// This is a class to create MWE (Ent)sperraufträge - /// - [TestClass] - public class TestSperrauftrag + private readonly JsonSerializerOptions _options = new() { - private readonly JsonSerializerOptions _options = new() - { - Converters = { new JsonStringEnumConverter() }, - IgnoreNullValues = true - }; + Converters = { new JsonStringEnumConverter() }, + IgnoreNullValues = true + }; - [TestMethod] - public void TestSperrauftragSerializationMaximal() + [TestMethod] + public void TestSperrauftragSerializationMaximal() + { + var sperrauftrag = new Sperrauftrag { - var sperrauftrag = new Sperrauftrag + Ausfuehrungsdatum = new DateTimeOffset(2022, 1, 5, 1, 1, 1, TimeSpan.Zero), + Bemerkungen = new List { "Der Typ erwartet uns mit Baseballschläger am Zähler" }, + Sparte = Sparte.STROM, + Zaehlernummer = "1YSE29183123", + Lieferanschrift = new Adresse { - Ausfuehrungsdatum = new DateTimeOffset(2022, 1, 5, 1, 1, 1, TimeSpan.Zero), - Bemerkungen = new List { "Der Typ erwartet uns mit Baseballschläger am Zähler" }, - Sparte = Sparte.STROM, - Zaehlernummer = "1YSE29183123", - Lieferanschrift = new Adresse - { - Strasse = "Rathausgasse", - Hausnummer = "8", - Landescode = Landescode.DE, - Postleitzahl = "04109", - Ort = "Leipzig" - }, - MarktlokationsId = "54321012345", - IstVomGerichtsvollzieherAngeordnet = true, - ExterneReferenzen = new List - { - new() - { - ExRefName = "Blocking service internal ID, you can choose any key here that you recognize", - ExRefWert = Guid.NewGuid().ToString(), - } - }, - Sperrauftragsstatus = Auftragsstatus.ZUGESTIMMT, - Mindestpreis = new Preis - { - Bezugswert = Mengeneinheit.ANZAHL, - Einheit = Waehrungseinheit.EUR, - Status = Preisstatus.VORLAEUFIG, - Wert = 10.00M - }, - Hoechstpreis = new Preis + Strasse = "Rathausgasse", + Hausnummer = "8", + Landescode = Landescode.DE, + Postleitzahl = "04109", + Ort = "Leipzig" + }, + MarktlokationsId = "54321012345", + IstVomGerichtsvollzieherAngeordnet = true, + ExterneReferenzen = new List + { + new() { - Bezugswert = Mengeneinheit.ANZAHL, - Einheit = Waehrungseinheit.EUR, - Status = Preisstatus.VORLAEUFIG, - Wert = 20.00M - }, - }; - sperrauftrag.IsValid().Should().BeTrue(); - var sperrauftragJson = JsonSerializer.Serialize(sperrauftrag, _options); - sperrauftragJson.Should().NotBe(null); - } + ExRefName = "Blocking service internal ID, you can choose any key here that you recognize", + ExRefWert = Guid.NewGuid().ToString(), + } + }, + Sperrauftragsstatus = Auftragsstatus.ZUGESTIMMT, + Mindestpreis = new Preis + { + Bezugswert = Mengeneinheit.ANZAHL, + Einheit = Waehrungseinheit.EUR, + Status = Preisstatus.VORLAEUFIG, + Wert = 10.00M + }, + Hoechstpreis = new Preis + { + Bezugswert = Mengeneinheit.ANZAHL, + Einheit = Waehrungseinheit.EUR, + Status = Preisstatus.VORLAEUFIG, + Wert = 20.00M + }, + }; + sperrauftrag.IsValid().Should().BeTrue(); + var sperrauftragJson = JsonSerializer.Serialize(sperrauftrag, _options); + sperrauftragJson.Should().NotBe(null); + } - [TestMethod] - public void TestSperrauftragSerializationMinimal() + [TestMethod] + public void TestSperrauftragSerializationMinimal() + { + var sperrauftrag = new Sperrauftrag { - var sperrauftrag = new Sperrauftrag + Ausfuehrungsdatum = new DateTimeOffset(2022, 1, 5, 1, 1, 1, TimeSpan.Zero), + Lieferanschrift = new Adresse { - Ausfuehrungsdatum = new DateTimeOffset(2022, 1, 5, 1, 1, 1, TimeSpan.Zero), - Lieferanschrift = new Adresse - { - Strasse = "Rathausgasse", - Hausnummer = "8", - Landescode = Landescode.DE, - Postleitzahl = "04109", - Ort = "Leipzig" - }, - MarktlokationsId = "54321012345", - IstVomGerichtsvollzieherAngeordnet = true, - }; - sperrauftrag.IsValid().Should().BeTrue(); - var sperrauftragJson = JsonSerializer.Serialize(sperrauftrag, _options); - sperrauftragJson.Should().NotBe(null); - } + Strasse = "Rathausgasse", + Hausnummer = "8", + Landescode = Landescode.DE, + Postleitzahl = "04109", + Ort = "Leipzig" + }, + MarktlokationsId = "54321012345", + IstVomGerichtsvollzieherAngeordnet = true, + }; + sperrauftrag.IsValid().Should().BeTrue(); + var sperrauftragJson = JsonSerializer.Serialize(sperrauftrag, _options); + sperrauftragJson.Should().NotBe(null); + } - [TestMethod] - public void TestEntsperrauftragMaximal() + [TestMethod] + public void TestEntsperrauftragMaximal() + { + var entsperrauftrag = new Entsperrauftrag { - var entsperrauftrag = new Entsperrauftrag + Ausfuehrungsdatum = new DateTimeOffset(2022, 6, 15, 1, 1, 1, TimeSpan.Zero), + Bemerkungen = new List { "Der Typ erwartet uns mit Blumenstrauß am Eingang" }, + Lieferanschrift = new Adresse { - Ausfuehrungsdatum = new DateTimeOffset(2022, 6, 15, 1, 1, 1, TimeSpan.Zero), - Bemerkungen = new List { "Der Typ erwartet uns mit Blumenstrauß am Eingang" }, - Lieferanschrift = new Adresse - { - Strasse = "Rathausgasse", - Hausnummer = "8", - Landescode = Landescode.DE, - Postleitzahl = "04109", - Ort = "Leipzig" - }, - MarktlokationsId = "54321012345", - Zaehlernummer = "1Yasdasdasd", - IstNurInnerhalbDerArbeitszeitZuEntsperren = true, - ExterneReferenzen = new List + Strasse = "Rathausgasse", + Hausnummer = "8", + Landescode = Landescode.DE, + Postleitzahl = "04109", + Ort = "Leipzig" + }, + MarktlokationsId = "54321012345", + Zaehlernummer = "1Yasdasdasd", + IstNurInnerhalbDerArbeitszeitZuEntsperren = true, + ExterneReferenzen = new List + { + new() { - new() - { - ExRefName = "Blocking service internal ID", - ExRefWert = Guid.NewGuid().ToString(), - } + ExRefName = "Blocking service internal ID", + ExRefWert = Guid.NewGuid().ToString(), } - }; - entsperrauftrag.IsValid().Should().BeTrue(); - var entsperrauftragJson = JsonSerializer.Serialize(entsperrauftrag, _options); - entsperrauftragJson.Should().NotBe(null); - } + } + }; + entsperrauftrag.IsValid().Should().BeTrue(); + var entsperrauftragJson = JsonSerializer.Serialize(entsperrauftrag, _options); + entsperrauftragJson.Should().NotBe(null); } } \ No newline at end of file diff --git a/BO4ETestProject/TestStringEnumConverter.cs b/BO4ETestProject/TestStringEnumConverter.cs index 10f4b412..d24946de 100644 --- a/BO4ETestProject/TestStringEnumConverter.cs +++ b/BO4ETestProject/TestStringEnumConverter.cs @@ -12,384 +12,383 @@ using Newtonsoft.Json.Converters; using JsonSerializer = System.Text.Json.JsonSerializer; -namespace TestBO4E +namespace TestBO4E; + +/// +/// gasqualitaet enum before https://github.com/Hochfrequenz/BO4E-dotnet/pull/508 +/// +/// I opened a bug at System.Text for this: https://github.com/dotnet/runtime/issues/107296 +public enum LegacyGasQualitaet { - /// - /// gasqualitaet enum before https://github.com/Hochfrequenz/BO4E-dotnet/pull/508 - /// - /// I opened a bug at System.Text for this: https://github.com/dotnet/runtime/issues/107296 - public enum LegacyGasQualitaet - { - /// High Caloric Gas - [EnumMember(Value = "H_GAS")] H_GAS = 1, + /// High Caloric Gas + [EnumMember(Value = "H_GAS")] H_GAS = 1, - /// Low Caloric Gas - [EnumMember(Value = "L_GAS")] L_GAS = 2, + /// Low Caloric Gas + [EnumMember(Value = "L_GAS")] L_GAS = 2, - /// High Caloric Gas - [EnumMember(Value = "HGAS")] HGAS = 1, + /// High Caloric Gas + [EnumMember(Value = "HGAS")] HGAS = 1, - /// Low Caloric Gas - [EnumMember(Value = "LGAS")] LGAS = 2, - } + /// Low Caloric Gas + [EnumMember(Value = "LGAS")] LGAS = 2, +} + +public class SomethingWithGasqualitaet +{ + public LegacyGasQualitaet Gasqualitaet { get; set; } +} + + + +[TestClass] +public class TestStringEnumConverter +{ + private readonly IList einheiten = new List + { + Mengeneinheit.TAG + }; - public class SomethingWithGasqualitaet + [TestMethod] + public void TestMengeneinheitNewtonsoft() { - public LegacyGasQualitaet Gasqualitaet { get; set; } + var jsonString = JsonConvert.SerializeObject(einheiten, new StringEnumConverter()); + Assert.IsTrue(jsonString.Contains("TAG")); } + [TestMethod] + public void TestMengeneinheit() + { + var options = new JsonSerializerOptions + { + Converters = { new StringNullableEnumConverter() } + }; + var jsonString = JsonSerializer.Serialize(einheiten, options); + Assert.IsTrue(jsonString.Contains("TAG")); + } + [TestMethod] + [DataRow(LegacyGasQualitaet.LGAS)] + [DataRow(LegacyGasQualitaet.L_GAS)] + [DataRow(LegacyGasQualitaet.HGAS)] + [DataRow(LegacyGasQualitaet.H_GAS)] + [Ignore("This test/the newtonsoft.json code path just worked accidentally, as a commenter in https://github.com/dotnet/runtime/issues/107296 pointed out")] + public void Test_Newtonsoft_With_Degenerate_Enum(LegacyGasQualitaet qualiaet) + { + var jsonString = JsonConvert.SerializeObject(new SomethingWithGasqualitaet + { + Gasqualitaet = qualiaet + }, new StringEnumConverter()); + jsonString.Should().ContainAny("H_GAS", "L_GAS").And.NotContainAny("HGAS", "LGAS"); + } - [TestClass] - public class TestStringEnumConverter + [TestMethod] + [DataRow(LegacyGasQualitaet.LGAS)] + [DataRow(LegacyGasQualitaet.L_GAS)] + [DataRow(LegacyGasQualitaet.HGAS)] // as of 2024-09-03 both H-GAS test cases fail but both L-GAS test cases pass 🤯 + [DataRow(LegacyGasQualitaet.H_GAS)] + [Ignore("this test fails but at least I understand it now: See https://github.com/dotnet/runtime/issues/107296")] + public void Test_System_Text_With_Degenerate_Enum(LegacyGasQualitaet qualiaet) { - private readonly IList einheiten = new List + var options = new JsonSerializerOptions { - Mengeneinheit.TAG + Converters = { new JsonStringEnumConverter() } }; + var jsonString = JsonSerializer.Serialize(new SomethingWithGasqualitaet + { + Gasqualitaet = qualiaet + }, options); + jsonString.Should().ContainAny("H_GAS", "L_GAS").And.NotContainAny("HGAS", "LGAS"); + } + + public class ClassWithNullableGasqualitaet + { + public Gasqualitaet? Foo { get; set; } + } + + public class ClassWithNonNullableGasqualitaet + { + public Gasqualitaet? Foo { get; set; } + } - [TestMethod] - public void TestMengeneinheitNewtonsoft() + [TestMethod] + [DataRow("HGAS", Gasqualitaet.H_GAS)] + [DataRow("H_GAS", Gasqualitaet.H_GAS)] + [DataRow("LGAS", Gasqualitaet.L_GAS)] + [DataRow("L_GAS", Gasqualitaet.L_GAS)] + [DataRow(null, null)] + public void Test_System_Text_Gasqualitaet_Legacy_Converter_With_Nullable_Gasqualitaet(string? jsonValue, Gasqualitaet? expectedGasqualitaet) + { + string jsonString; + if (jsonValue != null) { - var jsonString = JsonConvert.SerializeObject(einheiten, new StringEnumConverter()); - Assert.IsTrue(jsonString.Contains("TAG")); + jsonString = "{\"Foo\": \"" + jsonValue + "\"}"; } - - [TestMethod] - public void TestMengeneinheit() + else { - var options = new JsonSerializerOptions - { - Converters = { new StringNullableEnumConverter() } - }; - var jsonString = JsonSerializer.Serialize(einheiten, options); - Assert.IsTrue(jsonString.Contains("TAG")); + jsonString = "{\"Foo\": null}"; } - [TestMethod] - [DataRow(LegacyGasQualitaet.LGAS)] - [DataRow(LegacyGasQualitaet.L_GAS)] - [DataRow(LegacyGasQualitaet.HGAS)] - [DataRow(LegacyGasQualitaet.H_GAS)] - [Ignore("This test/the newtonsoft.json code path just worked accidentally, as a commenter in https://github.com/dotnet/runtime/issues/107296 pointed out")] - public void Test_Newtonsoft_With_Degenerate_Enum(LegacyGasQualitaet qualiaet) + var settings = new JsonSerializerOptions { Converters = { new SystemTextGasqualitaetStringEnumConverter() } }; + var actual = System.Text.Json.JsonSerializer.Deserialize(jsonString, settings); + actual.Should().NotBeNull(); + actual.Foo.Should().Be(expectedGasqualitaet); + + var reSerializedJsonString = System.Text.Json.JsonSerializer.Serialize(actual, settings); + reSerializedJsonString.Should().Contain(expectedGasqualitaet?.ToString() ?? "null"); + } + + [TestMethod] + [DataRow("HGAS", Gasqualitaet.H_GAS)] + [DataRow("H_GAS", Gasqualitaet.H_GAS)] + [DataRow("LGAS", Gasqualitaet.L_GAS)] + [DataRow("L_GAS", Gasqualitaet.L_GAS)] + public void Test_System_Text_Gasqualitaet_Legacy_Converter_With_Non_Nullable_Gasqualitaet(string? jsonValue, Gasqualitaet expectedGasqualitaet) + { + string jsonString; + if (jsonValue != null) { - var jsonString = JsonConvert.SerializeObject(new SomethingWithGasqualitaet - { - Gasqualitaet = qualiaet - }, new StringEnumConverter()); - jsonString.Should().ContainAny("H_GAS", "L_GAS").And.NotContainAny("HGAS", "LGAS"); + jsonString = "{\"Foo\": \"" + jsonValue + "\"}"; } - - [TestMethod] - [DataRow(LegacyGasQualitaet.LGAS)] - [DataRow(LegacyGasQualitaet.L_GAS)] - [DataRow(LegacyGasQualitaet.HGAS)] // as of 2024-09-03 both H-GAS test cases fail but both L-GAS test cases pass 🤯 - [DataRow(LegacyGasQualitaet.H_GAS)] - [Ignore("this test fails but at least I understand it now: See https://github.com/dotnet/runtime/issues/107296")] - public void Test_System_Text_With_Degenerate_Enum(LegacyGasQualitaet qualiaet) + else { - var options = new JsonSerializerOptions - { - Converters = { new JsonStringEnumConverter() } - }; - var jsonString = JsonSerializer.Serialize(new SomethingWithGasqualitaet - { - Gasqualitaet = qualiaet - }, options); - jsonString.Should().ContainAny("H_GAS", "L_GAS").And.NotContainAny("HGAS", "LGAS"); + jsonString = "{\"Foo\": null}"; } + var settings = new JsonSerializerOptions { Converters = { new SystemTextGasqualitaetStringEnumConverter() } }; + var actual = System.Text.Json.JsonSerializer.Deserialize(jsonString, settings); + actual.Should().NotBeNull(); + actual.Foo.Should().Be(expectedGasqualitaet); - public class ClassWithNullableGasqualitaet + var reSerializedJsonString = System.Text.Json.JsonSerializer.Serialize(actual, settings); + reSerializedJsonString.Should().Contain(expectedGasqualitaet.ToString()); + } + + [TestMethod] + [DataRow("HGAS", Gasqualitaet.H_GAS)] + [DataRow("H_GAS", Gasqualitaet.H_GAS)] + [DataRow("LGAS", Gasqualitaet.L_GAS)] + [DataRow("L_GAS", Gasqualitaet.L_GAS)] + [DataRow(null, null)] + public void Test_Newtonsoft_Gasqualitaet_Legacy_Converter_With_Nullable_Gasqualitaet(string? jsonValue, Gasqualitaet? expectedGasqualitaet) + { + string jsonString; + if (jsonValue != null) { - public Gasqualitaet? Foo { get; set; } + jsonString = "{\"Foo\": \"" + jsonValue + "\"}"; } - - public class ClassWithNonNullableGasqualitaet + else { - public Gasqualitaet? Foo { get; set; } + jsonString = "{\"Foo\": null}"; } - [TestMethod] - [DataRow("HGAS", Gasqualitaet.H_GAS)] - [DataRow("H_GAS", Gasqualitaet.H_GAS)] - [DataRow("LGAS", Gasqualitaet.L_GAS)] - [DataRow("L_GAS", Gasqualitaet.L_GAS)] - [DataRow(null, null)] - public void Test_System_Text_Gasqualitaet_Legacy_Converter_With_Nullable_Gasqualitaet(string? jsonValue, Gasqualitaet? expectedGasqualitaet) + var settings = new Newtonsoft.Json.JsonSerializerSettings() { - string jsonString; - if (jsonValue != null) - { - jsonString = "{\"Foo\": \"" + jsonValue + "\"}"; - } - else - { - jsonString = "{\"Foo\": null}"; - } - - var settings = new JsonSerializerOptions { Converters = { new SystemTextGasqualitaetStringEnumConverter() } }; - var actual = System.Text.Json.JsonSerializer.Deserialize(jsonString, settings); - actual.Should().NotBeNull(); - actual.Foo.Should().Be(expectedGasqualitaet); - - var reSerializedJsonString = System.Text.Json.JsonSerializer.Serialize(actual, settings); - reSerializedJsonString.Should().Contain(expectedGasqualitaet?.ToString() ?? "null"); - } + Converters = { new NewtonsoftGasqualitaetStringEnumConverter(), new StringEnumConverter() } + }; + var actual = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString, settings); + actual.Should().NotBeNull(); + actual.Foo.Should().Be(expectedGasqualitaet); - [TestMethod] - [DataRow("HGAS", Gasqualitaet.H_GAS)] - [DataRow("H_GAS", Gasqualitaet.H_GAS)] - [DataRow("LGAS", Gasqualitaet.L_GAS)] - [DataRow("L_GAS", Gasqualitaet.L_GAS)] - public void Test_System_Text_Gasqualitaet_Legacy_Converter_With_Non_Nullable_Gasqualitaet(string? jsonValue, Gasqualitaet expectedGasqualitaet) + var reSerializedJsonString = Newtonsoft.Json.JsonConvert.SerializeObject(actual, settings); + reSerializedJsonString.Should().Contain(expectedGasqualitaet?.ToString() ?? "null"); + } + + [TestMethod] + [DataRow("HGAS", Gasqualitaet.H_GAS)] + [DataRow("H_GAS", Gasqualitaet.H_GAS)] + [DataRow("LGAS", Gasqualitaet.L_GAS)] + [DataRow("L_GAS", Gasqualitaet.L_GAS)] + public void Test_Newtonsoft_Gasqualitaet_Legacy_Converter_With_Non_Nullable_Gasqualitaet(string? jsonValue, Gasqualitaet expectedGasqualitaet) + { + string jsonString; + if (jsonValue != null) { - string jsonString; - if (jsonValue != null) - { - jsonString = "{\"Foo\": \"" + jsonValue + "\"}"; - } - else - { - jsonString = "{\"Foo\": null}"; - } - var settings = new JsonSerializerOptions { Converters = { new SystemTextGasqualitaetStringEnumConverter() } }; - var actual = System.Text.Json.JsonSerializer.Deserialize(jsonString, settings); - actual.Should().NotBeNull(); - actual.Foo.Should().Be(expectedGasqualitaet); - - var reSerializedJsonString = System.Text.Json.JsonSerializer.Serialize(actual, settings); - reSerializedJsonString.Should().Contain(expectedGasqualitaet.ToString()); + jsonString = "{\"Foo\": \"" + jsonValue + "\"}"; } - - [TestMethod] - [DataRow("HGAS", Gasqualitaet.H_GAS)] - [DataRow("H_GAS", Gasqualitaet.H_GAS)] - [DataRow("LGAS", Gasqualitaet.L_GAS)] - [DataRow("L_GAS", Gasqualitaet.L_GAS)] - [DataRow(null, null)] - public void Test_Newtonsoft_Gasqualitaet_Legacy_Converter_With_Nullable_Gasqualitaet(string? jsonValue, Gasqualitaet? expectedGasqualitaet) + else { - string jsonString; - if (jsonValue != null) - { - jsonString = "{\"Foo\": \"" + jsonValue + "\"}"; - } - else - { - jsonString = "{\"Foo\": null}"; - } - - var settings = new Newtonsoft.Json.JsonSerializerSettings() - { - Converters = { new NewtonsoftGasqualitaetStringEnumConverter(), new StringEnumConverter() } - }; - var actual = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString, settings); - actual.Should().NotBeNull(); - actual.Foo.Should().Be(expectedGasqualitaet); - - var reSerializedJsonString = Newtonsoft.Json.JsonConvert.SerializeObject(actual, settings); - reSerializedJsonString.Should().Contain(expectedGasqualitaet?.ToString() ?? "null"); + jsonString = "{\"Foo\": null}"; } - [TestMethod] - [DataRow("HGAS", Gasqualitaet.H_GAS)] - [DataRow("H_GAS", Gasqualitaet.H_GAS)] - [DataRow("LGAS", Gasqualitaet.L_GAS)] - [DataRow("L_GAS", Gasqualitaet.L_GAS)] - public void Test_Newtonsoft_Gasqualitaet_Legacy_Converter_With_Non_Nullable_Gasqualitaet(string? jsonValue, Gasqualitaet expectedGasqualitaet) + var settings = new Newtonsoft.Json.JsonSerializerSettings() { - string jsonString; - if (jsonValue != null) - { - jsonString = "{\"Foo\": \"" + jsonValue + "\"}"; - } - else - { - jsonString = "{\"Foo\": null}"; - } - - var settings = new Newtonsoft.Json.JsonSerializerSettings() - { - Converters = { new NewtonsoftGasqualitaetStringEnumConverter(), new StringEnumConverter() } - }; - var actual = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString, settings); - actual.Should().NotBeNull(); - actual.Foo.Should().Be(expectedGasqualitaet); - - var reSerializedJsonString = Newtonsoft.Json.JsonConvert.SerializeObject(actual, settings); - reSerializedJsonString.Should().Contain(expectedGasqualitaet.ToString()); - } + Converters = { new NewtonsoftGasqualitaetStringEnumConverter(), new StringEnumConverter() } + }; + var actual = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString, settings); + actual.Should().NotBeNull(); + actual.Foo.Should().Be(expectedGasqualitaet); + var reSerializedJsonString = Newtonsoft.Json.JsonConvert.SerializeObject(actual, settings); + reSerializedJsonString.Should().Contain(expectedGasqualitaet.ToString()); + } - [TestMethod] - [DataRow(1, Gasqualitaet.H_GAS)] - [DataRow(2, Gasqualitaet.L_GAS)] - public void Test_SystemText_Gasqualitaet_Legacy_Converter_With_Non_Nullable_Gasqualitaet_Integer(int jsonValue, Gasqualitaet expectedGasqualitaet) - { - string jsonString = "{\"Foo\": " + jsonValue + "}"; - var settings = new JsonSerializerOptions { Converters = { new SystemTextGasqualitaetStringEnumConverter() } }; - var actual = System.Text.Json.JsonSerializer.Deserialize(jsonString, settings); - actual.Should().NotBeNull(); - actual.Foo.Should().Be(expectedGasqualitaet); - - var reSerializedJsonString = System.Text.Json.JsonSerializer.Serialize(actual, settings); - reSerializedJsonString.Should().Contain(expectedGasqualitaet.ToString()); - } - [TestMethod] - [DataRow(1, Gasqualitaet.H_GAS)] - [DataRow(2, Gasqualitaet.L_GAS)] - public void Test_Newtonsoft_Gasqualitaet_Legacy_Converter_With_Non_Nullable_Gasqualitaet_Integer(int jsonValue, Gasqualitaet expectedGasqualitaet) + [TestMethod] + [DataRow(1, Gasqualitaet.H_GAS)] + [DataRow(2, Gasqualitaet.L_GAS)] + public void Test_SystemText_Gasqualitaet_Legacy_Converter_With_Non_Nullable_Gasqualitaet_Integer(int jsonValue, Gasqualitaet expectedGasqualitaet) + { + string jsonString = "{\"Foo\": " + jsonValue + "}"; + var settings = new JsonSerializerOptions { Converters = { new SystemTextGasqualitaetStringEnumConverter() } }; + var actual = System.Text.Json.JsonSerializer.Deserialize(jsonString, settings); + actual.Should().NotBeNull(); + actual.Foo.Should().Be(expectedGasqualitaet); + + var reSerializedJsonString = System.Text.Json.JsonSerializer.Serialize(actual, settings); + reSerializedJsonString.Should().Contain(expectedGasqualitaet.ToString()); + } + + [TestMethod] + [DataRow(1, Gasqualitaet.H_GAS)] + [DataRow(2, Gasqualitaet.L_GAS)] + public void Test_Newtonsoft_Gasqualitaet_Legacy_Converter_With_Non_Nullable_Gasqualitaet_Integer(int jsonValue, Gasqualitaet expectedGasqualitaet) + { + string jsonString = "{\"Foo\": " + jsonValue + "}"; + var settings = new Newtonsoft.Json.JsonSerializerSettings() { - string jsonString = "{\"Foo\": " + jsonValue + "}"; - var settings = new Newtonsoft.Json.JsonSerializerSettings() - { - Converters = { new NewtonsoftGasqualitaetStringEnumConverter(), new StringEnumConverter() } - }; - var actual = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString, settings); - actual.Should().NotBeNull(); - actual.Foo.Should().Be(expectedGasqualitaet); - - var reSerializedJsonString = Newtonsoft.Json.JsonConvert.SerializeObject(actual, settings); - reSerializedJsonString.Should().Contain(expectedGasqualitaet.ToString()); - } + Converters = { new NewtonsoftGasqualitaetStringEnumConverter(), new StringEnumConverter() } + }; + var actual = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString, settings); + actual.Should().NotBeNull(); + actual.Foo.Should().Be(expectedGasqualitaet); - public class ClassWithNullableVerwendungszweck + var reSerializedJsonString = Newtonsoft.Json.JsonConvert.SerializeObject(actual, settings); + reSerializedJsonString.Should().Contain(expectedGasqualitaet.ToString()); + } + + public class ClassWithNullableVerwendungszweck + { + public Verwendungszweck? Foo { get; set; } + } + + public class ClassWithNonNullableVerwendungszweck + { + public Verwendungszweck Foo { get; set; } + } + + [TestMethod] + [DataRow("MEHRMINDERMENGENABRECHNUNG", Verwendungszweck.MEHRMINDERMENGENABRECHNUNG)] + [DataRow("MEHRMINDERMBENGENABRECHNUNG", Verwendungszweck.MEHRMINDERMENGENABRECHNUNG)] + [DataRow(null, null)] + public void Test_System_Text_Verwendungszweck_Legacy_Converter_With_Nullable_Verwendungszweck(string? jsonValue, Verwendungszweck? expectedVerwendungszweck) + { + string jsonString; + if (jsonValue != null) { - public Verwendungszweck? Foo { get; set; } + jsonString = "{\"Foo\": \"" + jsonValue + "\"}"; } - - public class ClassWithNonNullableVerwendungszweck + else { - public Verwendungszweck Foo { get; set; } + jsonString = "{\"Foo\": null}"; } - [TestMethod] - [DataRow("MEHRMINDERMENGENABRECHNUNG", Verwendungszweck.MEHRMINDERMENGENABRECHNUNG)] - [DataRow("MEHRMINDERMBENGENABRECHNUNG", Verwendungszweck.MEHRMINDERMENGENABRECHNUNG)] - [DataRow(null, null)] - public void Test_System_Text_Verwendungszweck_Legacy_Converter_With_Nullable_Verwendungszweck(string? jsonValue, Verwendungszweck? expectedVerwendungszweck) + var settings = new JsonSerializerOptions { Converters = { new SystemTextVerwendungszweckStringEnumConverter() } }; + var actual = System.Text.Json.JsonSerializer.Deserialize(jsonString, settings); + actual.Should().NotBeNull(); + actual.Foo.Should().Be(expectedVerwendungszweck); + + var reSerializedJsonString = System.Text.Json.JsonSerializer.Serialize(actual, settings); + reSerializedJsonString.Should().Contain(expectedVerwendungszweck?.ToString() ?? "null"); + } + + [TestMethod] + [DataRow("MEHRMINDERMENGENABRECHNUNG", Verwendungszweck.MEHRMINDERMENGENABRECHNUNG)] + [DataRow("MEHRMINDERMBENGENABRECHNUNG", Verwendungszweck.MEHRMINDERMENGENABRECHNUNG)] + public void Test_System_Text_Gasqualitaet_Legacy_Converter_With_Non_Nullable_Gasqualitaet(string? jsonValue, Verwendungszweck expectedVerwendungszweck) + { + string jsonString; + if (jsonValue != null) { - string jsonString; - if (jsonValue != null) - { - jsonString = "{\"Foo\": \"" + jsonValue + "\"}"; - } - else - { - jsonString = "{\"Foo\": null}"; - } - - var settings = new JsonSerializerOptions { Converters = { new SystemTextVerwendungszweckStringEnumConverter() } }; - var actual = System.Text.Json.JsonSerializer.Deserialize(jsonString, settings); - actual.Should().NotBeNull(); - actual.Foo.Should().Be(expectedVerwendungszweck); - - var reSerializedJsonString = System.Text.Json.JsonSerializer.Serialize(actual, settings); - reSerializedJsonString.Should().Contain(expectedVerwendungszweck?.ToString() ?? "null"); + jsonString = "{\"Foo\": \"" + jsonValue + "\"}"; } - - [TestMethod] - [DataRow("MEHRMINDERMENGENABRECHNUNG", Verwendungszweck.MEHRMINDERMENGENABRECHNUNG)] - [DataRow("MEHRMINDERMBENGENABRECHNUNG", Verwendungszweck.MEHRMINDERMENGENABRECHNUNG)] - public void Test_System_Text_Gasqualitaet_Legacy_Converter_With_Non_Nullable_Gasqualitaet(string? jsonValue, Verwendungszweck expectedVerwendungszweck) + else { - string jsonString; - if (jsonValue != null) - { - jsonString = "{\"Foo\": \"" + jsonValue + "\"}"; - } - else - { - jsonString = "{\"Foo\": null}"; - } - var settings = new JsonSerializerOptions { Converters = { new SystemTextVerwendungszweckStringEnumConverter() } }; - var actual = System.Text.Json.JsonSerializer.Deserialize(jsonString, settings); - actual.Should().NotBeNull(); - actual.Foo.Should().Be(expectedVerwendungszweck); - - var reSerializedJsonString = System.Text.Json.JsonSerializer.Serialize(actual, settings); - reSerializedJsonString.Should().Contain(expectedVerwendungszweck.ToString()); + jsonString = "{\"Foo\": null}"; } + var settings = new JsonSerializerOptions { Converters = { new SystemTextVerwendungszweckStringEnumConverter() } }; + var actual = System.Text.Json.JsonSerializer.Deserialize(jsonString, settings); + actual.Should().NotBeNull(); + actual.Foo.Should().Be(expectedVerwendungszweck); + + var reSerializedJsonString = System.Text.Json.JsonSerializer.Serialize(actual, settings); + reSerializedJsonString.Should().Contain(expectedVerwendungszweck.ToString()); + } - [TestMethod] - [DataRow("MEHRMINDERMENGENABRECHNUNG", Verwendungszweck.MEHRMINDERMENGENABRECHNUNG)] - [DataRow("MEHRMINDERMBENGENABRECHNUNG", Verwendungszweck.MEHRMINDERMENGENABRECHNUNG)] - [DataRow(null, null)] - public void Test_Newtonsoft_Verwendungszweck_Legacy_Converter_With_Nullable_Verwendungszweck(string? jsonValue, Verwendungszweck? expectedVerwendungszweck) + [TestMethod] + [DataRow("MEHRMINDERMENGENABRECHNUNG", Verwendungszweck.MEHRMINDERMENGENABRECHNUNG)] + [DataRow("MEHRMINDERMBENGENABRECHNUNG", Verwendungszweck.MEHRMINDERMENGENABRECHNUNG)] + [DataRow(null, null)] + public void Test_Newtonsoft_Verwendungszweck_Legacy_Converter_With_Nullable_Verwendungszweck(string? jsonValue, Verwendungszweck? expectedVerwendungszweck) + { + string jsonString; + if (jsonValue != null) { - string jsonString; - if (jsonValue != null) - { - jsonString = "{\"Foo\": \"" + jsonValue + "\"}"; - } - else - { - jsonString = "{\"Foo\": null}"; - } - - var settings = new Newtonsoft.Json.JsonSerializerSettings() - { - Converters = { new NewtonsoftVerwendungszweckStringEnumConverter(), new StringEnumConverter() } - }; - var actual = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString, settings); - actual.Should().NotBeNull(); - actual.Foo.Should().Be(expectedVerwendungszweck); - - var reSerializedJsonString = Newtonsoft.Json.JsonConvert.SerializeObject(actual, settings); - reSerializedJsonString.Should().Contain(expectedVerwendungszweck?.ToString() ?? "null"); + jsonString = "{\"Foo\": \"" + jsonValue + "\"}"; } - - [TestMethod] - [DataRow("MEHRMINDERMENGENABRECHNUNG", Verwendungszweck.MEHRMINDERMENGENABRECHNUNG)] - [DataRow("MEHRMINDERMBENGENABRECHNUNG", Verwendungszweck.MEHRMINDERMENGENABRECHNUNG)] - public void Test_Newtonsoft_Verwendungszweck_Legacy_Converter_With_Non_Nullable_Verwendungszweck(string? jsonValue, Verwendungszweck expectedVerwendungszweck) + else { - string jsonString = "{\"Foo\": \"" + jsonValue + "\"}"; - var settings = new Newtonsoft.Json.JsonSerializerSettings() - { - Converters = { new NewtonsoftVerwendungszweckStringEnumConverter(), new StringEnumConverter() } - }; - var actual = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString, settings); - actual.Should().NotBeNull(); - actual.Foo.Should().Be(expectedVerwendungszweck); - - var reSerializedJsonString = Newtonsoft.Json.JsonConvert.SerializeObject(actual, settings); - reSerializedJsonString.Should().Contain(expectedVerwendungszweck.ToString()); + jsonString = "{\"Foo\": null}"; } - [TestMethod] - [DataRow((int)Verwendungszweck.MEHRMINDERMENGENABRECHNUNG, Verwendungszweck.MEHRMINDERMENGENABRECHNUNG)] - public void Test_SystemText_Verwendungszweck_Legacy_Converter_With_Non_Nullable_Verwendungszweck_Integer(int jsonValue, Verwendungszweck expectedVerwendungszweck) + var settings = new Newtonsoft.Json.JsonSerializerSettings() { - string jsonString = "{\"Foo\": " + jsonValue + "}"; - var settings = new JsonSerializerOptions { Converters = { new SystemTextVerwendungszweckStringEnumConverter(), new JsonStringEnumConverter() } }; - var actual = System.Text.Json.JsonSerializer.Deserialize(jsonString, settings); - actual.Should().NotBeNull(); - actual.Foo.Should().Be(expectedVerwendungszweck); - - var reSerializedJsonString = System.Text.Json.JsonSerializer.Serialize(actual, settings); - reSerializedJsonString.Should().Contain(expectedVerwendungszweck.ToString()); - } + Converters = { new NewtonsoftVerwendungszweckStringEnumConverter(), new StringEnumConverter() } + }; + var actual = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString, settings); + actual.Should().NotBeNull(); + actual.Foo.Should().Be(expectedVerwendungszweck); + + var reSerializedJsonString = Newtonsoft.Json.JsonConvert.SerializeObject(actual, settings); + reSerializedJsonString.Should().Contain(expectedVerwendungszweck?.ToString() ?? "null"); + } - [TestMethod] - [DataRow((int)Verwendungszweck.MEHRMINDERMENGENABRECHNUNG, Verwendungszweck.MEHRMINDERMENGENABRECHNUNG)] - public void Test_Newtonsoft_Verwendungszweck_Legacy_Converter_With_Non_Nullable_Verwendungszweck_Integer(int jsonValue, Verwendungszweck expectedVerwendungszweck) + [TestMethod] + [DataRow("MEHRMINDERMENGENABRECHNUNG", Verwendungszweck.MEHRMINDERMENGENABRECHNUNG)] + [DataRow("MEHRMINDERMBENGENABRECHNUNG", Verwendungszweck.MEHRMINDERMENGENABRECHNUNG)] + public void Test_Newtonsoft_Verwendungszweck_Legacy_Converter_With_Non_Nullable_Verwendungszweck(string? jsonValue, Verwendungszweck expectedVerwendungszweck) + { + string jsonString = "{\"Foo\": \"" + jsonValue + "\"}"; + var settings = new Newtonsoft.Json.JsonSerializerSettings() { - string jsonString = "{\"Foo\": " + jsonValue + "}"; - var settings = new Newtonsoft.Json.JsonSerializerSettings() - { - Converters = { new NewtonsoftVerwendungszweckStringEnumConverter(), new StringEnumConverter() } - }; - var actual = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString, settings); - actual.Should().NotBeNull(); - actual.Foo.Should().Be(expectedVerwendungszweck); - - var reSerializedJsonString = Newtonsoft.Json.JsonConvert.SerializeObject(actual, settings); - reSerializedJsonString.Should().Contain(expectedVerwendungszweck.ToString()); - } + Converters = { new NewtonsoftVerwendungszweckStringEnumConverter(), new StringEnumConverter() } + }; + var actual = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString, settings); + actual.Should().NotBeNull(); + actual.Foo.Should().Be(expectedVerwendungszweck); + var reSerializedJsonString = Newtonsoft.Json.JsonConvert.SerializeObject(actual, settings); + reSerializedJsonString.Should().Contain(expectedVerwendungszweck.ToString()); } -} + + [TestMethod] + [DataRow((int)Verwendungszweck.MEHRMINDERMENGENABRECHNUNG, Verwendungszweck.MEHRMINDERMENGENABRECHNUNG)] + public void Test_SystemText_Verwendungszweck_Legacy_Converter_With_Non_Nullable_Verwendungszweck_Integer(int jsonValue, Verwendungszweck expectedVerwendungszweck) + { + string jsonString = "{\"Foo\": " + jsonValue + "}"; + var settings = new JsonSerializerOptions { Converters = { new SystemTextVerwendungszweckStringEnumConverter(), new JsonStringEnumConverter() } }; + var actual = System.Text.Json.JsonSerializer.Deserialize(jsonString, settings); + actual.Should().NotBeNull(); + actual.Foo.Should().Be(expectedVerwendungszweck); + + var reSerializedJsonString = System.Text.Json.JsonSerializer.Serialize(actual, settings); + reSerializedJsonString.Should().Contain(expectedVerwendungszweck.ToString()); + } + + [TestMethod] + [DataRow((int)Verwendungszweck.MEHRMINDERMENGENABRECHNUNG, Verwendungszweck.MEHRMINDERMENGENABRECHNUNG)] + public void Test_Newtonsoft_Verwendungszweck_Legacy_Converter_With_Non_Nullable_Verwendungszweck_Integer(int jsonValue, Verwendungszweck expectedVerwendungszweck) + { + string jsonString = "{\"Foo\": " + jsonValue + "}"; + var settings = new Newtonsoft.Json.JsonSerializerSettings() + { + Converters = { new NewtonsoftVerwendungszweckStringEnumConverter(), new StringEnumConverter() } + }; + var actual = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString, settings); + actual.Should().NotBeNull(); + actual.Foo.Should().Be(expectedVerwendungszweck); + + var reSerializedJsonString = Newtonsoft.Json.JsonConvert.SerializeObject(actual, settings); + reSerializedJsonString.Should().Contain(expectedVerwendungszweck.ToString()); + } + +} \ No newline at end of file diff --git a/BO4ETestProject/TestUserProperties.cs b/BO4ETestProject/TestUserProperties.cs index 9a5c7a4f..fc96f0c2 100644 --- a/BO4ETestProject/TestUserProperties.cs +++ b/BO4ETestProject/TestUserProperties.cs @@ -12,251 +12,250 @@ using Newtonsoft.Json; using JsonSerializer = System.Text.Json.JsonSerializer; -namespace TestBO4E +namespace TestBO4E; + +[TestClass] +public class TestUserProperties { - [TestClass] - public class TestUserProperties - { - private const string meloJson = - @"{""messlokationsId"": ""DE0123456789012345678901234567890"", ""sparte"": ""STROM"", ""myCustomInfo"": ""some_value_not_covered_by_bo4e"", ""myCustomValue"": 123.456, ""myNullProp"": null}"; + private const string meloJson = + @"{""messlokationsId"": ""DE0123456789012345678901234567890"", ""sparte"": ""STROM"", ""myCustomInfo"": ""some_value_not_covered_by_bo4e"", ""myCustomValue"": 123.456, ""myNullProp"": null}"; - [TestMethod] - public void TestNetExample() - { - using var r = new StreamReader("testjsons/weatherforecast.json"); - var jsonString = r.ReadToEnd(); - var zaehler = JsonSerializer.Deserialize(jsonString); - } + [TestMethod] + public void TestNetExample() + { + using var r = new StreamReader("testjsons/weatherforecast.json"); + var jsonString = r.ReadToEnd(); + var zaehler = JsonSerializer.Deserialize(jsonString); + } - [TestMethod] - public void TestDeserialization() - { - var meloJson = - @"{'messlokationsId': 'DE0123456789012345678901234567890', 'sparte': 'STROM', 'myCustomInfo': 'some_value_not_covered_by_bo4e', 'myCustomValue': 123.456}"; - var melo = JsonConvert.DeserializeObject(meloJson); - Assert.IsTrue(melo.IsValid()); - Assert.IsNotNull(melo.UserProperties); - Assert.AreEqual("some_value_not_covered_by_bo4e", melo.UserProperties["myCustomInfo"] as string); - Assert.AreEqual(123.456M, (decimal)(double)melo.UserProperties["myCustomValue"]); - } + [TestMethod] + public void TestDeserialization() + { + var meloJson = + @"{'messlokationsId': 'DE0123456789012345678901234567890', 'sparte': 'STROM', 'myCustomInfo': 'some_value_not_covered_by_bo4e', 'myCustomValue': 123.456}"; + var melo = JsonConvert.DeserializeObject(meloJson); + Assert.IsTrue(melo.IsValid()); + Assert.IsNotNull(melo.UserProperties); + Assert.AreEqual("some_value_not_covered_by_bo4e", melo.UserProperties["myCustomInfo"] as string); + Assert.AreEqual(123.456M, (decimal)(double)melo.UserProperties["myCustomValue"]); + } - [TestMethod] - public void TestConvertingUserPropertyToBoolean() - { - var options = LenientParsing.MOST_LENIENT.GetJsonSerializerOptions(); - var meloJson = @"{""messlokationsId"": ""DE0123456789012345678901234567890"", ""sparte"": ""STROM"", ""myCustomInfo"": ""some_value_not_covered_by_bo4e"", ""myCustomValue"": ""not a boolean""}"; - var melo = JsonSerializer.Deserialize(meloJson, options); - melo.Should().NotBeNull(); - melo.IsValid().Should().BeTrue(); - melo.UserProperties.Should().NotBeEmpty(); - melo.UserProperties.Should().ContainKey("myCustomValue").WhoseValue.ToString().Should().Be("not a boolean"); + [TestMethod] + public void TestConvertingUserPropertyToBoolean() + { + var options = LenientParsing.MOST_LENIENT.GetJsonSerializerOptions(); + var meloJson = @"{""messlokationsId"": ""DE0123456789012345678901234567890"", ""sparte"": ""STROM"", ""myCustomInfo"": ""some_value_not_covered_by_bo4e"", ""myCustomValue"": ""not a boolean""}"; + var melo = JsonSerializer.Deserialize(meloJson, options); + melo.Should().NotBeNull(); + melo.IsValid().Should().BeTrue(); + melo.UserProperties.Should().NotBeEmpty(); + melo.UserProperties.Should().ContainKey("myCustomValue").WhoseValue.ToString().Should().Be("not a boolean"); - var flagHasBeenSet = melo.SetFlag("myCustomValue", true); - flagHasBeenSet.Should().BeTrue(because: "the non-boolean existing value (which is overwritten) should not crash the code"); - melo.TryGetUserProperty("myCustomValue", out bool booleanValue).Should().BeTrue(); - booleanValue.Should().BeTrue(); - } + var flagHasBeenSet = melo.SetFlag("myCustomValue", true); + flagHasBeenSet.Should().BeTrue(because: "the non-boolean existing value (which is overwritten) should not crash the code"); + melo.TryGetUserProperty("myCustomValue", out bool booleanValue).Should().BeTrue(); + booleanValue.Should().BeTrue(); + } - [TestMethod] - public void TestDeserializationSystemTextJson() - { - var options = LenientParsing.MOST_LENIENT.GetJsonSerializerOptions(); - var meloJson = - @"{""messlokationsId"": ""DE0123456789012345678901234567890"", ""sparte"": ""STROM"", ""myCustomInfo"": ""some_value_not_covered_by_bo4e"", ""myCustomValue"": 123.456}"; - var melo = JsonSerializer.Deserialize(meloJson, options); - Assert.IsTrue(melo.IsValid()); - Assert.IsNotNull(melo.UserProperties); - Assert.AreEqual("some_value_not_covered_by_bo4e", melo.UserProperties["myCustomInfo"].ToString()); - Assert.AreEqual(123.456M, ((JsonElement)melo.UserProperties["myCustomValue"]).GetDecimal()); - } + [TestMethod] + public void TestDeserializationSystemTextJson() + { + var options = LenientParsing.MOST_LENIENT.GetJsonSerializerOptions(); + var meloJson = + @"{""messlokationsId"": ""DE0123456789012345678901234567890"", ""sparte"": ""STROM"", ""myCustomInfo"": ""some_value_not_covered_by_bo4e"", ""myCustomValue"": 123.456}"; + var melo = JsonSerializer.Deserialize(meloJson, options); + Assert.IsTrue(melo.IsValid()); + Assert.IsNotNull(melo.UserProperties); + Assert.AreEqual("some_value_not_covered_by_bo4e", melo.UserProperties["myCustomInfo"].ToString()); + Assert.AreEqual(123.456M, ((JsonElement)melo.UserProperties["myCustomValue"]).GetDecimal()); + } - private void _AssertUserProperties(Messlokation melo) - { - Assert.IsTrue(melo.TryGetUserProperty("myCustomInfo", out string myCustomValue)); - Assert.AreEqual("some_value_not_covered_by_bo4e", myCustomValue); - Assert.IsTrue(melo.UserPropertyEquals("myCustomValue", 123.456M)); - Assert.IsFalse(melo.UserPropertyEquals("myCustomValue", "foo")); + private void _AssertUserProperties(Messlokation melo) + { + Assert.IsTrue(melo.TryGetUserProperty("myCustomInfo", out string myCustomValue)); + Assert.AreEqual("some_value_not_covered_by_bo4e", myCustomValue); + Assert.IsTrue(melo.UserPropertyEquals("myCustomValue", 123.456M)); + Assert.IsFalse(melo.UserPropertyEquals("myCustomValue", "foo")); - Assert.IsFalse(melo.TryGetUserProperty("something else", out string _)); - Assert.AreEqual("default value", melo.GetUserProperty("something else", "default value")); - Assert.IsFalse(melo.UserPropertyEquals("myCustomInfo", 888.999M)); // the cast exception is catched inside. - Assert.IsFalse(melo.UserPropertyEquals("myCustomValue", "asd")); // the cast exception is catched inside. - Assert.IsFalse(melo.UserPropertyEquals("some_key_that_was_not_found", "asd")); - Assert.IsTrue( - melo.EvaluateUserProperty("myCustomInfo", up => !string.IsNullOrEmpty(up))); + Assert.IsFalse(melo.TryGetUserProperty("something else", out string _)); + Assert.AreEqual("default value", melo.GetUserProperty("something else", "default value")); + Assert.IsFalse(melo.UserPropertyEquals("myCustomInfo", 888.999M)); // the cast exception is catched inside. + Assert.IsFalse(melo.UserPropertyEquals("myCustomValue", "asd")); // the cast exception is catched inside. + Assert.IsFalse(melo.UserPropertyEquals("some_key_that_was_not_found", "asd")); + Assert.IsTrue( + melo.EvaluateUserProperty("myCustomInfo", up => !string.IsNullOrEmpty(up))); - melo.UserProperties = null; - Assert.IsFalse(melo.UserPropertyEquals("there are no user properties", "asd")); - Assert.IsFalse(melo.TryGetUserProperty("there are no user properties", out string _)); - Assert.ThrowsException(() => - melo.EvaluateUserProperty("there are no user properties", _ => default)); - Assert.IsFalse(melo.UserPropertyEquals("myNullProp", true)); - } + melo.UserProperties = null; + Assert.IsFalse(melo.UserPropertyEquals("there are no user properties", "asd")); + Assert.IsFalse(melo.TryGetUserProperty("there are no user properties", out string _)); + Assert.ThrowsException(() => + melo.EvaluateUserProperty("there are no user properties", _ => default)); + Assert.IsFalse(melo.UserPropertyEquals("myNullProp", true)); + } - [TestMethod] - public void TestTryGetUserProperties() - { - var melo = JsonConvert.DeserializeObject(meloJson); - _AssertUserProperties(melo); - } + [TestMethod] + public void TestTryGetUserProperties() + { + var melo = JsonConvert.DeserializeObject(meloJson); + _AssertUserProperties(melo); + } - [TestMethod] - public void TestTryGetUserPropertiesNet5() - { - var options = LenientParsing.STRICT.GetJsonSerializerOptions(); - var melo = JsonSerializer.Deserialize(meloJson, options); - _AssertUserProperties(melo); - } + [TestMethod] + public void TestTryGetUserPropertiesNet5() + { + var options = LenientParsing.STRICT.GetJsonSerializerOptions(); + var melo = JsonSerializer.Deserialize(meloJson, options); + _AssertUserProperties(melo); + } - [TestMethod] - public void TestFlags() + [TestMethod] + public void TestFlags() + { + var melo = new Messlokation { - var melo = new Messlokation - { - MesslokationsId = "DE0123456789012345678901234567890", - Sparte = Sparte.STROM - }; - Assert.IsNull(melo.UserProperties); - Assert.IsFalse(melo.HasFlagSet("foo")); - Assert.IsTrue(melo.SetFlag("foo")); - Assert.IsNotNull(melo.UserProperties); - Assert.IsTrue(melo.UserProperties.TryGetValue("foo", out var upValue) && (bool)upValue); - Assert.IsTrue(melo.HasFlagSet("foo")); - Assert.IsFalse(melo.SetFlag("foo")); - Assert.IsTrue(melo.SetFlag("foo", false)); - Assert.IsFalse(melo.HasFlagSet("foo")); - Assert.IsTrue(melo.SetFlag("foo", null)); - Assert.IsFalse(melo.UserProperties.TryGetValue("foo", out var _)); - Assert.IsFalse(melo.SetFlag("foo", null)); - Assert.IsFalse(melo.HasFlagSet("foo")); - Assert.IsTrue(melo.SetFlag("foo")); + MesslokationsId = "DE0123456789012345678901234567890", + Sparte = Sparte.STROM + }; + Assert.IsNull(melo.UserProperties); + Assert.IsFalse(melo.HasFlagSet("foo")); + Assert.IsTrue(melo.SetFlag("foo")); + Assert.IsNotNull(melo.UserProperties); + Assert.IsTrue(melo.UserProperties.TryGetValue("foo", out var upValue) && (bool)upValue); + Assert.IsTrue(melo.HasFlagSet("foo")); + Assert.IsFalse(melo.SetFlag("foo")); + Assert.IsTrue(melo.SetFlag("foo", false)); + Assert.IsFalse(melo.HasFlagSet("foo")); + Assert.IsTrue(melo.SetFlag("foo", null)); + Assert.IsFalse(melo.UserProperties.TryGetValue("foo", out var _)); + Assert.IsFalse(melo.SetFlag("foo", null)); + Assert.IsFalse(melo.HasFlagSet("foo")); + Assert.IsTrue(melo.SetFlag("foo")); - melo.UserProperties["foo"] = null; - Assert.IsFalse(melo.HasFlagSet("foo")); - } + melo.UserProperties["foo"] = null; + Assert.IsFalse(melo.HasFlagSet("foo")); + } - /// - /// Tests to set and get a UserProperty - /// - [TestMethod] - public void TestSetterGetter() + /// + /// Tests to set and get a UserProperty + /// + [TestMethod] + public void TestSetterGetter() + { + var melo = new Messlokation { - var melo = new Messlokation - { - MesslokationsId = "DE0123456789012345678901234567890", - Sparte = Sparte.STROM - }; - Assert.IsNull(melo.UserProperties); + MesslokationsId = "DE0123456789012345678901234567890", + Sparte = Sparte.STROM + }; + Assert.IsNull(melo.UserProperties); - var value1 = "BarFoo"; - var value2 = "BigFoot"; - melo.SetUserProperty("foo", new Bar { FooBar = value1 }); - Assert.IsNotNull(melo.UserProperties); - Assert.IsTrue(melo.UserProperties.TryGetValue("foo", out var upValue)); - Assert.IsInstanceOfType(upValue, typeof(Bar)); - Assert.AreEqual(value1, (upValue as Bar)?.FooBar); + var value1 = "BarFoo"; + var value2 = "BigFoot"; + melo.SetUserProperty("foo", new Bar { FooBar = value1 }); + Assert.IsNotNull(melo.UserProperties); + Assert.IsTrue(melo.UserProperties.TryGetValue("foo", out var upValue)); + Assert.IsInstanceOfType(upValue, typeof(Bar)); + Assert.AreEqual(value1, (upValue as Bar)?.FooBar); - // Update the value - melo.SetUserProperty("foo", new Bar { FooBar = value2 }); - Assert.IsTrue(melo.UserProperties.TryGetValue("foo", out upValue)); - Assert.AreEqual(value2, (upValue as Bar)?.FooBar); - } + // Update the value + melo.SetUserProperty("foo", new Bar { FooBar = value2 }); + Assert.IsTrue(melo.UserProperties.TryGetValue("foo", out upValue)); + Assert.AreEqual(value2, (upValue as Bar)?.FooBar); + } - /// - /// Tests to remove UserProperty - /// - [TestMethod] - public void TestDeletion() + /// + /// Tests to remove UserProperty + /// + [TestMethod] + public void TestDeletion() + { + var melo = new Messlokation { - var melo = new Messlokation - { - MesslokationsId = "DE0123456789012345678901234567890", - Sparte = Sparte.STROM - }; - Assert.IsNull(melo.UserProperties); + MesslokationsId = "DE0123456789012345678901234567890", + Sparte = Sparte.STROM + }; + Assert.IsNull(melo.UserProperties); - var value1 = "BarFoo"; - // Add a value - melo.SetUserProperty("foo", new Bar { FooBar = value1 }); - Assert.IsNotNull(melo.UserProperties); - Assert.IsTrue(melo.UserProperties.TryGetValue("foo", out var upValue)); - Assert.AreEqual(value1, (upValue as Bar)?.FooBar); - // remove it again - melo.RemoveUserProperty("foo"); - Assert.IsFalse(melo.UserProperties.TryGetValue("foo", out upValue)); - Assert.IsNotNull(melo.UserProperties); - } + var value1 = "BarFoo"; + // Add a value + melo.SetUserProperty("foo", new Bar { FooBar = value1 }); + Assert.IsNotNull(melo.UserProperties); + Assert.IsTrue(melo.UserProperties.TryGetValue("foo", out var upValue)); + Assert.AreEqual(value1, (upValue as Bar)?.FooBar); + // remove it again + melo.RemoveUserProperty("foo"); + Assert.IsFalse(melo.UserProperties.TryGetValue("foo", out upValue)); + Assert.IsNotNull(melo.UserProperties); + } - public class WeatherForecastWithExtensionData - { - public DateTimeOffset Date { get; set; } - public int TemperatureCelsius { get; set; } - public string Summary { get; set; } + public class WeatherForecastWithExtensionData + { + public DateTimeOffset Date { get; set; } + public int TemperatureCelsius { get; set; } + public string Summary { get; set; } - [System.Text.Json.Serialization.JsonExtensionData] - public Dictionary ExtensionData { get; set; } - } + [System.Text.Json.Serialization.JsonExtensionData] + public Dictionary ExtensionData { get; set; } + } - /// - /// Test Class to append a UserProperty - /// - private class Bar - { - public string FooBar; - } + /// + /// Test Class to append a UserProperty + /// + private class Bar + { + public string FooBar; + } - [TestMethod] - public void TestBusinessObjectHasAmbiguousUserProperties() + [TestMethod] + public void TestBusinessObjectHasAmbiguousUserProperties() + { + var zaehlerWithAmbiguousProperties = new Zaehler() { - var zaehlerWithAmbiguousProperties = new Zaehler() + Zaehlergroesse = Geraetemerkmal.GAS_G6, + UserProperties = new Dictionary { - Zaehlergroesse = Geraetemerkmal.GAS_G6, - UserProperties = new Dictionary - { - {"zaehlergroesse", "Foo"}, - {"BoTyp", "Dei Mudder"} - } - }; - zaehlerWithAmbiguousProperties.HasAmbiguousUserProperties().Should().BeTrue(); - zaehlerWithAmbiguousProperties.GetAmbiguousUserPropertiesKeys().Should() - .Contain("zaehlergroesse") - .And.Contain("BoTyp") - .And.HaveCount(2); + {"zaehlergroesse", "Foo"}, + {"BoTyp", "Dei Mudder"} + } + }; + zaehlerWithAmbiguousProperties.HasAmbiguousUserProperties().Should().BeTrue(); + zaehlerWithAmbiguousProperties.GetAmbiguousUserPropertiesKeys().Should() + .Contain("zaehlergroesse") + .And.Contain("BoTyp") + .And.HaveCount(2); - var zaehlerWithoutAmbiguousProperties = new Zaehler() - { - Zaehlergroesse = Geraetemerkmal.GAS_G6, - UserProperties = new Dictionary { { "foo", "bar" } } - }; - zaehlerWithoutAmbiguousProperties.HasAmbiguousUserProperties().Should().BeFalse(); - zaehlerWithoutAmbiguousProperties.GetAmbiguousUserPropertiesKeys().Should().BeEmpty(); - } + var zaehlerWithoutAmbiguousProperties = new Zaehler() + { + Zaehlergroesse = Geraetemerkmal.GAS_G6, + UserProperties = new Dictionary { { "foo", "bar" } } + }; + zaehlerWithoutAmbiguousProperties.HasAmbiguousUserProperties().Should().BeFalse(); + zaehlerWithoutAmbiguousProperties.GetAmbiguousUserPropertiesKeys().Should().BeEmpty(); + } - [TestMethod] - public void TestComHasAmbiguousUserProperties() + [TestMethod] + public void TestComHasAmbiguousUserProperties() + { + var adresseWithAmbiguousProperties = new Adresse() { - var adresseWithAmbiguousProperties = new Adresse() + Hausnummer = "17", + UserProperties = new Dictionary { - Hausnummer = "17", - UserProperties = new Dictionary - { - {"Hausnummer", 423}, - {"Postleitzahl", "foobar"}, - } - }; - adresseWithAmbiguousProperties.HasAmbiguousUserProperties().Should().BeTrue(); - adresseWithAmbiguousProperties.GetAmbiguousUserPropertiesKeys().Should() - .Contain("Hausnummer") - .And.Contain("Postleitzahl") - .And.HaveCount(2); + {"Hausnummer", 423}, + {"Postleitzahl", "foobar"}, + } + }; + adresseWithAmbiguousProperties.HasAmbiguousUserProperties().Should().BeTrue(); + adresseWithAmbiguousProperties.GetAmbiguousUserPropertiesKeys().Should() + .Contain("Hausnummer") + .And.Contain("Postleitzahl") + .And.HaveCount(2); - var adresseWithoutAmbiguousProperties = new Adresse() - { - Hausnummer = "17", - UserProperties = new Dictionary { { "foo", "bar" } } - }; - adresseWithoutAmbiguousProperties.HasAmbiguousUserProperties().Should().BeFalse(); - adresseWithoutAmbiguousProperties.GetAmbiguousUserPropertiesKeys().Should().BeEmpty(); - } + var adresseWithoutAmbiguousProperties = new Adresse() + { + Hausnummer = "17", + UserProperties = new Dictionary { { "foo", "bar" } } + }; + adresseWithoutAmbiguousProperties.HasAmbiguousUserProperties().Should().BeFalse(); + adresseWithoutAmbiguousProperties.GetAmbiguousUserPropertiesKeys().Should().BeEmpty(); } -} +} \ No newline at end of file diff --git a/BO4ETestProject/TestZeitraumDeserialization.cs b/BO4ETestProject/TestZeitraumDeserialization.cs index 0f2bba5c..00d3fe28 100644 --- a/BO4ETestProject/TestZeitraumDeserialization.cs +++ b/BO4ETestProject/TestZeitraumDeserialization.cs @@ -8,49 +8,48 @@ using Newtonsoft.Json; using Newtonsoft.Json.Converters; -namespace TestBO4E +namespace TestBO4E; + +[TestClass] +public class TestZeitraumDeserialization { - [TestClass] - public class TestZeitraumDeserialization + private void _TestZeitraumDeserialization(Func serializer, Func deserializer) { - private void _TestZeitraumDeserialization(Func serializer, Func deserializer) + var zeitraum = new Zeitraum { - var zeitraum = new Zeitraum - { - Startdatum = new DateTimeOffset(2022, 1, 1, 0, 0, 0, TimeSpan.Zero), - Enddatum = new DateTimeOffset(2022, 1, 2, 0, 0, 0, TimeSpan.Zero), - }; - var jsonString = serializer(zeitraum); - var jsonDict = System.Text.Json.JsonSerializer.Deserialize>(jsonString); // we deserialize into an anonymous dict just to be decoupled from the json hacks, it is not important that we use system.text for that - jsonDict["startdatum"].Should().NotBeNull(); - jsonDict["enddatum"].Should().NotBeNull(); - jsonDict["startzeitpunkt"].Should().BeEquivalentTo(jsonDict["startdatum"]); - jsonDict["endzeitpunkt"].Should().BeEquivalentTo(jsonDict["endzeitpunkt"]); + Startdatum = new DateTimeOffset(2022, 1, 1, 0, 0, 0, TimeSpan.Zero), + Enddatum = new DateTimeOffset(2022, 1, 2, 0, 0, 0, TimeSpan.Zero), + }; + var jsonString = serializer(zeitraum); + var jsonDict = System.Text.Json.JsonSerializer.Deserialize>(jsonString); // we deserialize into an anonymous dict just to be decoupled from the json hacks, it is not important that we use system.text for that + jsonDict["startdatum"].Should().NotBeNull(); + jsonDict["enddatum"].Should().NotBeNull(); + jsonDict["startzeitpunkt"].Should().BeEquivalentTo(jsonDict["startdatum"]); + jsonDict["endzeitpunkt"].Should().BeEquivalentTo(jsonDict["endzeitpunkt"]); - // now we remove the datümer and deserialize again into a zeitraum - jsonDict.Remove("startdatum"); - jsonDict.Remove("enddatum"); + // now we remove the datümer and deserialize again into a zeitraum + jsonDict.Remove("startdatum"); + jsonDict.Remove("enddatum"); - jsonString = System.Text.Json.JsonSerializer.Serialize(jsonDict); - var deserializedZeitraum = deserializer(jsonString); - deserializedZeitraum.Should().BeEquivalentTo(zeitraum, opts => opts.Excluding(zr => zr.Dauer).Excluding(zr => zr.Einheit)); - // excluding the two props because they are part of a not so glorious hack `FillNullValues` in the Zeitraum class which I don't want to touch here. - } + jsonString = System.Text.Json.JsonSerializer.Serialize(jsonDict); + var deserializedZeitraum = deserializer(jsonString); + deserializedZeitraum.Should().BeEquivalentTo(zeitraum, opts => opts.Excluding(zr => zr.Dauer).Excluding(zr => zr.Einheit)); + // excluding the two props because they are part of a not so glorious hack `FillNullValues` in the Zeitraum class which I don't want to touch here. + } - [TestMethod] - public void TestZeitraumDeserializationNewtonsoft() - { - _TestZeitraumDeserialization(zr => JsonConvert.SerializeObject(zr, new StringEnumConverter()), str => JsonConvert.DeserializeObject(str)); - } + [TestMethod] + public void TestZeitraumDeserializationNewtonsoft() + { + _TestZeitraumDeserialization(zr => JsonConvert.SerializeObject(zr, new StringEnumConverter()), str => JsonConvert.DeserializeObject(str)); + } - [TestMethod] - public void TestZeitraumDeserializationSystemText() + [TestMethod] + public void TestZeitraumDeserializationSystemText() + { + var jsonOptions = new JsonSerializerOptions() { - var jsonOptions = new JsonSerializerOptions() - { - Converters = { new JsonStringEnumConverter() } - }; - _TestZeitraumDeserialization(zr => System.Text.Json.JsonSerializer.Serialize(zr, jsonOptions), str => System.Text.Json.JsonSerializer.Deserialize(str, jsonOptions)); - } + Converters = { new JsonStringEnumConverter() } + }; + _TestZeitraumDeserialization(zr => System.Text.Json.JsonSerializer.Serialize(zr, jsonOptions), str => System.Text.Json.JsonSerializer.Deserialize(str, jsonOptions)); } -} +} \ No newline at end of file diff --git a/TestBO4E.Extensions/ShowCaseTests/EnergiemengeShowCaseTests.cs b/TestBO4E.Extensions/ShowCaseTests/EnergiemengeShowCaseTests.cs index 546cedec..ec7acc0c 100644 --- a/TestBO4E.Extensions/ShowCaseTests/EnergiemengeShowCaseTests.cs +++ b/TestBO4E.Extensions/ShowCaseTests/EnergiemengeShowCaseTests.cs @@ -9,54 +9,53 @@ using Itenso.TimePeriod; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace TestBO4E.Extensions.ShowCaseTests +namespace TestBO4E.Extensions.ShowCaseTests; + +[TestClass] +public class EnergiemengeShowCaseTests { - [TestClass] - public class EnergiemengeShowCaseTests + [TestMethod] + public void ShowCaseTest() { - [TestMethod] - public void ShowCaseTest() + var em = new Energiemenge { - var em = new Energiemenge + LokationsId = "DE0123456789012345678901234567890", + LokationsTyp = Lokationstyp.MELO, + Energieverbrauch = new List { - LokationsId = "DE0123456789012345678901234567890", - LokationsTyp = Lokationstyp.MELO, - Energieverbrauch = new List + new Verbrauch + { + Einheit = Mengeneinheit.KWH, + Startdatum = new DateTime(2020, 3, 1, 0, 0, 0, DateTimeKind.Utc), + Enddatum = new DateTime(2020, 3, 8, 0, 0, 0, DateTimeKind.Utc), + Wert = 456.0M, + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG + }, + new Verbrauch { - new Verbrauch - { - Einheit = Mengeneinheit.KWH, - Startdatum = new DateTime(2020, 3, 1, 0, 0, 0, DateTimeKind.Utc), - Enddatum = new DateTime(2020, 3, 8, 0, 0, 0, DateTimeKind.Utc), - Wert = 456.0M, - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG - }, - new Verbrauch - { - Einheit = Mengeneinheit.KWH, - Startdatum = new DateTime(2020, 3, 25, 0, 0, 0, DateTimeKind.Utc), - Enddatum = new DateTime(2020, 4, 1, 0, 0, 0, DateTimeKind.Utc), - Wert = 123.0M, - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG - } + Einheit = Mengeneinheit.KWH, + Startdatum = new DateTime(2020, 3, 25, 0, 0, 0, DateTimeKind.Utc), + Enddatum = new DateTime(2020, 4, 1, 0, 0, 0, DateTimeKind.Utc), + Wert = 123.0M, + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG } - }; - Debug.WriteLine( - $"You got Verbrauch data for {decimal.Round(em.GetCoverage() * 100.0M)}% of the time in between {em.Energieverbrauch.Select(v => v.Startdatum).Min():yyyy-MM-dd} and {em.Energieverbrauch.Select(v => v.Enddatum).Max():yyyy-MM-dd}"); - // You got Verbrauch data for 45% of the time in between 2020-03-01 and 2020-04-01 + } + }; + Debug.WriteLine( + $"You got Verbrauch data for {decimal.Round(em.GetCoverage() * 100.0M)}% of the time in between {em.Energieverbrauch.Select(v => v.Startdatum).Min():yyyy-MM-dd} and {em.Energieverbrauch.Select(v => v.Enddatum).Max():yyyy-MM-dd}"); + // You got Verbrauch data for 45% of the time in between 2020-03-01 and 2020-04-01 - var consumption = em.GetTotalConsumption(); - Debug.WriteLine($"The total consumption is {consumption.Item1}{consumption.Item2}"); - // The total consumption is 579,0KWH + var consumption = em.GetTotalConsumption(); + Debug.WriteLine($"The total consumption is {consumption.Item1}{consumption.Item2}"); + // The total consumption is 579,0KWH - var consumptionMarch7 = em.GetConsumption(new TimeRange( - new DateTimeOffset(2020, 3, 7, 0, 0, 0, TimeSpan.Zero).UtcDateTime, - new DateTimeOffset(2020, 3, 8, 0, 0, 0, TimeSpan.Zero).UtcDateTime)); - Debug.WriteLine( - $"The total consumption on March 7 is {decimal.Round(consumptionMarch7.Item1)}{consumptionMarch7.Item2}"); - // The total consumption on March 7 is 65KWH + var consumptionMarch7 = em.GetConsumption(new TimeRange( + new DateTimeOffset(2020, 3, 7, 0, 0, 0, TimeSpan.Zero).UtcDateTime, + new DateTimeOffset(2020, 3, 8, 0, 0, 0, TimeSpan.Zero).UtcDateTime)); + Debug.WriteLine( + $"The total consumption on March 7 is {decimal.Round(consumptionMarch7.Item1)}{consumptionMarch7.Item2}"); + // The total consumption on March 7 is 65KWH - // ToDo: show other methods. - } + // ToDo: show other methods. } } \ No newline at end of file diff --git a/TestBO4E.Extensions/ShowCaseTests/VerbrauchShowCaseTests.cs b/TestBO4E.Extensions/ShowCaseTests/VerbrauchShowCaseTests.cs index fceed126..e28018f2 100644 --- a/TestBO4E.Extensions/ShowCaseTests/VerbrauchShowCaseTests.cs +++ b/TestBO4E.Extensions/ShowCaseTests/VerbrauchShowCaseTests.cs @@ -5,51 +5,50 @@ using BO4E.Extensions.COM; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace TestBO4E.Extensions.ShowCaseTests +namespace TestBO4E.Extensions.ShowCaseTests; + +[TestClass] +public class VerbrauchShowCaseTests { - [TestClass] - public class VerbrauchShowCaseTests + [TestMethod] + public void ShowCaseTest() { - [TestMethod] - public void ShowCaseTest() + var verbrauchA = new Verbrauch { - var verbrauchA = new Verbrauch - { - Startdatum = new DateTime(2020, 3, 1, 0, 0, 0, DateTimeKind.Utc), - Enddatum = new DateTime(2020, 3, 8, 0, 0, 0, DateTimeKind.Utc), - Wert = 0.456M, - Einheit = Mengeneinheit.MW, - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG - }; + Startdatum = new DateTime(2020, 3, 1, 0, 0, 0, DateTimeKind.Utc), + Enddatum = new DateTime(2020, 3, 8, 0, 0, 0, DateTimeKind.Utc), + Wert = 0.456M, + Einheit = Mengeneinheit.MW, + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG + }; - verbrauchA.ConvertToUnit(Mengeneinheit.KW); - Debug.WriteLine($"{nameof(verbrauchA)} contains {verbrauchA.Wert}{verbrauchA.Einheit}"); - // v contains 456,000KW + verbrauchA.ConvertToUnit(Mengeneinheit.KW); + Debug.WriteLine($"{nameof(verbrauchA)} contains {verbrauchA.Wert}{verbrauchA.Einheit}"); + // v contains 456,000KW - try - { - verbrauchA.ConvertToUnit(Mengeneinheit.TAG); - } - catch (InvalidOperationException ioe) - { - Debug.WriteLine(ioe.Message); - // KW and TAG are not convertible into each other because they don't share the same dimension. - } + try + { + verbrauchA.ConvertToUnit(Mengeneinheit.TAG); + } + catch (InvalidOperationException ioe) + { + Debug.WriteLine(ioe.Message); + // KW and TAG are not convertible into each other because they don't share the same dimension. + } - var verbrauchB = new Verbrauch - { - Startdatum = new DateTime(2020, 3, 7, 0, 0, 0, DateTimeKind.Utc), - Enddatum = new DateTime(2020, 3, 14, 0, 0, 0, DateTimeKind.Utc), - Wert = 0.1M, - Einheit = Mengeneinheit.KW, - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG - }; + var verbrauchB = new Verbrauch + { + Startdatum = new DateTime(2020, 3, 7, 0, 0, 0, DateTimeKind.Utc), + Enddatum = new DateTime(2020, 3, 14, 0, 0, 0, DateTimeKind.Utc), + Wert = 0.1M, + Einheit = Mengeneinheit.KW, + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG + }; - foreach (var v in verbrauchA.Merge(verbrauchB)) - Debug.WriteLine($"{v.Startdatum:yyyy-MM-dd} to {v.Enddatum:yyyy-MM-dd}: {v.Wert}{v.Einheit}"); - // 2020-03-01 to 2020-03-07: 456,000KW - // 2020-03-07 to 2020-03-08: 456,100KW - // 2020-03-08 to 2020-03-14: 0,1KW - } + foreach (var v in verbrauchA.Merge(verbrauchB)) + Debug.WriteLine($"{v.Startdatum:yyyy-MM-dd} to {v.Enddatum:yyyy-MM-dd}: {v.Wert}{v.Einheit}"); + // 2020-03-01 to 2020-03-07: 456,000KW + // 2020-03-07 to 2020-03-08: 456,100KW + // 2020-03-08 to 2020-03-14: 0,1KW } } \ No newline at end of file diff --git a/TestBO4E.Extensions/TestBenachrichtigungExtension.cs b/TestBO4E.Extensions/TestBenachrichtigungExtension.cs index 336ad5db..65addf81 100644 --- a/TestBO4E.Extensions/TestBenachrichtigungExtension.cs +++ b/TestBO4E.Extensions/TestBenachrichtigungExtension.cs @@ -6,68 +6,67 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json; -namespace TestBO4E.Extensions +namespace TestBO4E.Extensions; + +[TestClass] +public class TestBenachrichtigungExtension { - [TestClass] - public class TestBenachrichtigungExtension + [TestMethod] + public void TestHas() { - [TestMethod] - public void TestHas() + var b = new Benachrichtigung { - var b = new Benachrichtigung + BenachrichtigungsId = "1234", + Bearbeiter = "dei mudder", + Infos = new List { - BenachrichtigungsId = "1234", - Bearbeiter = "dei mudder", - Infos = new List - { - new GenericStringStringInfo {KeyColumn = "ads", Value = "xyz"}, - new GenericStringStringInfo {KeyColumn = "null", Value = null} - } - }; + new GenericStringStringInfo {KeyColumn = "ads", Value = "xyz"}, + new GenericStringStringInfo {KeyColumn = "null", Value = null} + } + }; - Assert.IsTrue(b.Has("ads", "xyz")); - Assert.IsFalse(b.Has("null", "not-null")); - Assert.IsTrue(b.Has("null", null)); - Assert.IsFalse(b.Has("someothervalue", null)); - Assert.IsFalse(b.Has("someothervalue")); - Assert.IsTrue(b.Has("ads")); - Assert.IsTrue(b.Has("null")); - Assert.IsFalse(b.Has((string)null)); + Assert.IsTrue(b.Has("ads", "xyz")); + Assert.IsFalse(b.Has("null", "not-null")); + Assert.IsTrue(b.Has("null", null)); + Assert.IsFalse(b.Has("someothervalue", null)); + Assert.IsFalse(b.Has("someothervalue")); + Assert.IsTrue(b.Has("ads")); + Assert.IsTrue(b.Has("null")); + Assert.IsFalse(b.Has((string)null)); - Assert.IsFalse(new Benachrichtigung().Has("abc")); - } + Assert.IsFalse(new Benachrichtigung().Has("abc")); + } - [TestMethod] - public void TestMoveInfo2UP() - { - var b = JsonConvert.DeserializeObject( - "{\"versionStruktur\":1,\"boTyp\":\"BENACHRICHTIGUNG\",\"benachrichtigungsId\":\"468985\",\"prioritaet\":2,\"bearbeitungsstatus\":0,\"kurztext\":\"Manuelles Überschreiben von Profilwerten\",\"erstellungsZeitpunkt\":\"2019-04-01T14:27:23Z\",\"kategorie\":\"ZE01\",\"bearbeiter\":\"\",\"notizen\":null,\"deadline\":null,\"aufgaben\":null,\"infos\":null,\"aufgaben\":[{\"ccat\":\"ZE01\",\"objtype\":\"ZISUPROFIL\",\"aufgabenId\":\"OVERWRITE\",\"ausgefuehrt\":\"true\"},{\"ccat\":\"ZE01\",\"objtype\":\"ZISUPROFIL\",\"aufgabenId\":\"DISPLAY\",\"ausgefuehrt\":\"true\"}],\"infos\":[{\"keyColumn\":\"MESSLOKATIONSID\",\"value\":\"DE000360478090000000\",\"boolean_true_column\":false},{\"keyColumn\":\"TIMESPAN_FROM\",\"value\":\"2019-02-25T23:00:00Z\",\"boolean_true_column\":false},{\"keyColumn\":\"TIMESPAN_TO\",\"value\":\"2019-03-19T22:44:59Z\",\"boolean_true_column\":false}],\"notizen\":[]}"); - Assert.IsTrue(b.Has("MESSLOKATIONSID")); - Assert.IsTrue(b.UserProperties == null || b.UserProperties.Count == 0); - b.MoveInfosToUserProperties(); - Assert.IsNotNull(b.UserProperties); - Assert.IsTrue(b.UserProperties.ContainsKey("MESSLOKATIONSID")); - Assert.IsNull(b.Infos); - } + [TestMethod] + public void TestMoveInfo2UP() + { + var b = JsonConvert.DeserializeObject( + "{\"versionStruktur\":1,\"boTyp\":\"BENACHRICHTIGUNG\",\"benachrichtigungsId\":\"468985\",\"prioritaet\":2,\"bearbeitungsstatus\":0,\"kurztext\":\"Manuelles Überschreiben von Profilwerten\",\"erstellungsZeitpunkt\":\"2019-04-01T14:27:23Z\",\"kategorie\":\"ZE01\",\"bearbeiter\":\"\",\"notizen\":null,\"deadline\":null,\"aufgaben\":null,\"infos\":null,\"aufgaben\":[{\"ccat\":\"ZE01\",\"objtype\":\"ZISUPROFIL\",\"aufgabenId\":\"OVERWRITE\",\"ausgefuehrt\":\"true\"},{\"ccat\":\"ZE01\",\"objtype\":\"ZISUPROFIL\",\"aufgabenId\":\"DISPLAY\",\"ausgefuehrt\":\"true\"}],\"infos\":[{\"keyColumn\":\"MESSLOKATIONSID\",\"value\":\"DE000360478090000000\",\"boolean_true_column\":false},{\"keyColumn\":\"TIMESPAN_FROM\",\"value\":\"2019-02-25T23:00:00Z\",\"boolean_true_column\":false},{\"keyColumn\":\"TIMESPAN_TO\",\"value\":\"2019-03-19T22:44:59Z\",\"boolean_true_column\":false}],\"notizen\":[]}"); + Assert.IsTrue(b.Has("MESSLOKATIONSID")); + Assert.IsTrue(b.UserProperties == null || b.UserProperties.Count == 0); + b.MoveInfosToUserProperties(); + Assert.IsNotNull(b.UserProperties); + Assert.IsTrue(b.UserProperties.ContainsKey("MESSLOKATIONSID")); + Assert.IsNull(b.Infos); + } - [TestMethod] - public void TestHasWithMesslokationsId() - { - var b = JsonConvert.DeserializeObject( - "{\"versionStruktur\":1,\"boTyp\":\"BENACHRICHTIGUNG\",\"benachrichtigungsId\":\"483052\",\"prioritaet\":2,\"bearbeitungsstatus\":2,\"kurztext\":\"Manuelles Überschreiben von Profilwerten\",\"erstellungsZeitpunkt\":\"2019-05-22T12:14:32Z\",\"kategorie\":\"ZE01\",\"bearbeiter\":\"SCHLEBDA\",\"notizen\":[],\"deadline\":null,\"aufgaben\":[{\"aufgabenId\":\"OVERWRITE\",\"beschreibung\":null,\"deadline\":null,\"ausgefuehrt\":true,\"ausfuehrungszeitpunkt\":\"2019-05-22T12:18:50Z\",\"ausfuehrender\":\"SCHLEBDA\",\"ccat\":\"ZE01\",\"casenr\":\"483052\",\"objtype\":\"ZISUPROFIL\"},{\"aufgabenId\":\"DISPLAY\",\"beschreibung\":null,\"deadline\":null,\"ausgefuehrt\":false,\"ausfuehrungszeitpunkt\":null,\"ausfuehrender\":\"\",\"ccat\":\"ZE01\",\"casenr\":\"483052\",\"objtype\":\"ZISUPROFIL\"},{\"aufgabenId\":\"REIMPORT\",\"beschreibung\":null,\"deadline\":null,\"ausgefuehrt\":false,\"ausfuehrungszeitpunkt\":null,\"ausfuehrender\":\"\",\"ccat\":\"ZE01\",\"casenr\":\"483052\",\"objtype\":\"ZISUPROFIL\"},{\"aufgabenId\":\"EXTERN_IGNORE\",\"beschreibung\":null,\"deadline\":null,\"ausgefuehrt\":false,\"ausfuehrungszeitpunkt\":null,\"ausfuehrender\":\"\",\"ccat\":\"ZE01\",\"casenr\":\"483052\",\"objtype\":\"ZISUPROFIL\"}],\"infos\":[{\"keyColumn\":\"MESS\",\"value\":\"9905048000007\",\"boolean_true_column\":false},{\"keyColumn\":\"MESSLOKATIONSID\",\"value\":\"DE0003604780400000000000010000176\",\"boolean_true_column\":false},{\"keyColumn\":\"TIMESPAN_FROM\",\"value\":\"2019-04-16T22:00:00Z\",\"boolean_true_column\":false},{\"keyColumn\":\"TIMESPAN_TO\",\"value\":\"2019-04-17T21:59:59Z\",\"boolean_true_column\":false}],\"casenr\":\"483052\"}"); - Assert.IsTrue(b.Has("MESSLOKATIONSID")); // funktioniert wahrscheinlich - Assert.IsTrue(b.Has("MESSLOKATIONSID", "DE0003604780400000000000010000176")); - } + [TestMethod] + public void TestHasWithMesslokationsId() + { + var b = JsonConvert.DeserializeObject( + "{\"versionStruktur\":1,\"boTyp\":\"BENACHRICHTIGUNG\",\"benachrichtigungsId\":\"483052\",\"prioritaet\":2,\"bearbeitungsstatus\":2,\"kurztext\":\"Manuelles Überschreiben von Profilwerten\",\"erstellungsZeitpunkt\":\"2019-05-22T12:14:32Z\",\"kategorie\":\"ZE01\",\"bearbeiter\":\"SCHLEBDA\",\"notizen\":[],\"deadline\":null,\"aufgaben\":[{\"aufgabenId\":\"OVERWRITE\",\"beschreibung\":null,\"deadline\":null,\"ausgefuehrt\":true,\"ausfuehrungszeitpunkt\":\"2019-05-22T12:18:50Z\",\"ausfuehrender\":\"SCHLEBDA\",\"ccat\":\"ZE01\",\"casenr\":\"483052\",\"objtype\":\"ZISUPROFIL\"},{\"aufgabenId\":\"DISPLAY\",\"beschreibung\":null,\"deadline\":null,\"ausgefuehrt\":false,\"ausfuehrungszeitpunkt\":null,\"ausfuehrender\":\"\",\"ccat\":\"ZE01\",\"casenr\":\"483052\",\"objtype\":\"ZISUPROFIL\"},{\"aufgabenId\":\"REIMPORT\",\"beschreibung\":null,\"deadline\":null,\"ausgefuehrt\":false,\"ausfuehrungszeitpunkt\":null,\"ausfuehrender\":\"\",\"ccat\":\"ZE01\",\"casenr\":\"483052\",\"objtype\":\"ZISUPROFIL\"},{\"aufgabenId\":\"EXTERN_IGNORE\",\"beschreibung\":null,\"deadline\":null,\"ausgefuehrt\":false,\"ausfuehrungszeitpunkt\":null,\"ausfuehrender\":\"\",\"ccat\":\"ZE01\",\"casenr\":\"483052\",\"objtype\":\"ZISUPROFIL\"}],\"infos\":[{\"keyColumn\":\"MESS\",\"value\":\"9905048000007\",\"boolean_true_column\":false},{\"keyColumn\":\"MESSLOKATIONSID\",\"value\":\"DE0003604780400000000000010000176\",\"boolean_true_column\":false},{\"keyColumn\":\"TIMESPAN_FROM\",\"value\":\"2019-04-16T22:00:00Z\",\"boolean_true_column\":false},{\"keyColumn\":\"TIMESPAN_TO\",\"value\":\"2019-04-17T21:59:59Z\",\"boolean_true_column\":false}],\"casenr\":\"483052\"}"); + Assert.IsTrue(b.Has("MESSLOKATIONSID")); // funktioniert wahrscheinlich + Assert.IsTrue(b.Has("MESSLOKATIONSID", "DE0003604780400000000000010000176")); + } - [TestMethod] - public void TestDateTimePredicates() - { - var b = JsonConvert.DeserializeObject( - "{\"versionStruktur\":1,\"boTyp\":\"BENACHRICHTIGUNG\",\"benachrichtigungsId\":\"469568\",\"prioritaet\":2,\"bearbeitungsstatus\":1,\"kurztext\":\"Manuelles \u00dcberschreiben von Profilwerten\",\"erstellungsZeitpunkt\":\"2019-04-02T13:35:03Z\",\"kategorie\":\"ZE01\",\"bearbeiter\":\"SCHLEBDA\",\"notizen\":[],\"deadline\":null,\"aufgaben\":[{\"aufgabenId\":\"OVERWRITE\",\"beschreibung\":null,\"deadline\":null,\"ausgefuehrt\":true,\"ausfuehrungsdatum\":null,\"ausfuehrender\":null,\"ccat\":\"ZE01\",\"objtype\":\"ZISUPROFIL\"},{\"aufgabenId\":\"DISPLAY\",\"beschreibung\":null,\"deadline\":null,\"ausgefuehrt\":true,\"ausfuehrungsdatum\":null,\"ausfuehrender\":null,\"ccat\":\"ZE01\",\"objtype\":\"ZISUPROFIL\"}],\"infos\":null,\"MESS\":\"9977768000005\",\"MESSLOKATIONSID\":\"DE0003604763800000000000010376811\",\"TIMESPAN_FROM\":\"2019-03-11T23:30:00Z\",\"TIMESPAN_TO\":\"2019-03-12T22:59:59Z\"}"); - Assert.IsTrue(b.UserProperties.TryGetValue("TIMESPAN_FROM", out var jtLower)); - _ = (DateTime)jtLower; - Assert.IsTrue(b.UserProperties.TryGetValue("TIMESPAN_TO", out var jtUpper)); - _ = (DateTime)jtUpper; - } + [TestMethod] + public void TestDateTimePredicates() + { + var b = JsonConvert.DeserializeObject( + "{\"versionStruktur\":1,\"boTyp\":\"BENACHRICHTIGUNG\",\"benachrichtigungsId\":\"469568\",\"prioritaet\":2,\"bearbeitungsstatus\":1,\"kurztext\":\"Manuelles \u00dcberschreiben von Profilwerten\",\"erstellungsZeitpunkt\":\"2019-04-02T13:35:03Z\",\"kategorie\":\"ZE01\",\"bearbeiter\":\"SCHLEBDA\",\"notizen\":[],\"deadline\":null,\"aufgaben\":[{\"aufgabenId\":\"OVERWRITE\",\"beschreibung\":null,\"deadline\":null,\"ausgefuehrt\":true,\"ausfuehrungsdatum\":null,\"ausfuehrender\":null,\"ccat\":\"ZE01\",\"objtype\":\"ZISUPROFIL\"},{\"aufgabenId\":\"DISPLAY\",\"beschreibung\":null,\"deadline\":null,\"ausgefuehrt\":true,\"ausfuehrungsdatum\":null,\"ausfuehrender\":null,\"ccat\":\"ZE01\",\"objtype\":\"ZISUPROFIL\"}],\"infos\":null,\"MESS\":\"9977768000005\",\"MESSLOKATIONSID\":\"DE0003604763800000000000010376811\",\"TIMESPAN_FROM\":\"2019-03-11T23:30:00Z\",\"TIMESPAN_TO\":\"2019-03-12T22:59:59Z\"}"); + Assert.IsTrue(b.UserProperties.TryGetValue("TIMESPAN_FROM", out var jtLower)); + _ = (DateTime)jtLower; + Assert.IsTrue(b.UserProperties.TryGetValue("TIMESPAN_TO", out var jtUpper)); + _ = (DateTime)jtUpper; } } \ No newline at end of file diff --git a/TestBO4E.Extensions/TestCloningExtension.cs b/TestBO4E.Extensions/TestCloningExtension.cs index d258b16a..30992aea 100644 --- a/TestBO4E.Extensions/TestCloningExtension.cs +++ b/TestBO4E.Extensions/TestCloningExtension.cs @@ -6,61 +6,60 @@ using BO4E.Extensions.BusinessObjects; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace TestBO4E.Extensions +namespace TestBO4E.Extensions; + +[TestClass] +public class TestCloningExtension { - [TestClass] - public class TestCloningExtension + [TestMethod] + public void TestCloning() { - [TestMethod] - public void TestCloning() + var bo = new Messlokation { - var bo = new Messlokation - { - MesslokationsId = "DE345" - }; - var cloneBo = bo.DeepClone(); - Assert.AreNotSame(bo, cloneBo); - // Assert.AreEqual((Messlokation)bo, cloneBo); <--- keine ahnung warum das failed. vllt. auch mit json patch/diff arbeiten wie im hubnet projekt - } + MesslokationsId = "DE345" + }; + var cloneBo = bo.DeepClone(); + Assert.AreNotSame(bo, cloneBo); + // Assert.AreEqual((Messlokation)bo, cloneBo); <--- keine ahnung warum das failed. vllt. auch mit json patch/diff arbeiten wie im hubnet projekt + } - [TestMethod] - public void TestCloningEnergiemenge() + [TestMethod] + public void TestCloningEnergiemenge() + { + var em = new Energiemenge { - var em = new Energiemenge + LokationsId = "De12345", + LokationsTyp = Lokationstyp.MALO, + Energieverbrauch = new List { - LokationsId = "De12345", - LokationsTyp = Lokationstyp.MALO, - Energieverbrauch = new List + new Verbrauch + { + Einheit = Mengeneinheit.KWH, + Wert = 123.456M, + Obiskennzahl = "dei vadder", + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, + Startdatum = new DateTime(2018, 12, 31, 23, 0, 0, 0, DateTimeKind.Utc), + Enddatum = new DateTime(2019, 12, 31, 23, 0, 0, 0, DateTimeKind.Utc) + }, + new Verbrauch { - new Verbrauch - { - Einheit = Mengeneinheit.KWH, - Wert = 123.456M, - Obiskennzahl = "dei vadder", - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, - Startdatum = new DateTime(2018, 12, 31, 23, 0, 0, 0, DateTimeKind.Utc), - Enddatum = new DateTime(2019, 12, 31, 23, 0, 0, 0, DateTimeKind.Utc) - }, - new Verbrauch - { - Einheit = Mengeneinheit.KWH, - Wert = 789.123M, - Obiskennzahl = "dei mudder", - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, - Startdatum = new DateTime(2019, 12, 31, 23, 0, 0, 0, DateTimeKind.Utc), - Enddatum = new DateTime(2020, 12, 31, 23, 0, 0, 0, DateTimeKind.Utc) - } + Einheit = Mengeneinheit.KWH, + Wert = 789.123M, + Obiskennzahl = "dei mudder", + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, + Startdatum = new DateTime(2019, 12, 31, 23, 0, 0, 0, DateTimeKind.Utc), + Enddatum = new DateTime(2020, 12, 31, 23, 0, 0, 0, DateTimeKind.Utc) } - }; - var cloned = em.DeepClone(); - Assert.AreEqual(em.Energieverbrauch.Count, cloned.Energieverbrauch.Count); + } + }; + var cloned = em.DeepClone(); + Assert.AreEqual(em.Energieverbrauch.Count, cloned.Energieverbrauch.Count); - var cloned2 = em.DeepClone(); - Assert.AreEqual(em.Energieverbrauch.Count, cloned2.Energieverbrauch.Count); + var cloned2 = em.DeepClone(); + Assert.AreEqual(em.Energieverbrauch.Count, cloned2.Energieverbrauch.Count); - var cloned3 = ((BusinessObject)em).DeepClone(); - Assert.IsTrue(cloned3 is Energiemenge); - Assert.AreEqual(em.Energieverbrauch.Count, (cloned3 as Energiemenge).Energieverbrauch.Count); - } + var cloned3 = ((BusinessObject)em).DeepClone(); + Assert.IsTrue(cloned3 is Energiemenge); + Assert.AreEqual(em.Energieverbrauch.Count, (cloned3 as Energiemenge).Energieverbrauch.Count); } } \ No newline at end of file diff --git a/TestBO4E.Extensions/TestEnergiemengeExtension.cs b/TestBO4E.Extensions/TestEnergiemengeExtension.cs index 2445a49a..30bfbdd5 100644 --- a/TestBO4E.Extensions/TestEnergiemengeExtension.cs +++ b/TestBO4E.Extensions/TestEnergiemengeExtension.cs @@ -5,40 +5,39 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json; -namespace TestBO4E.Extensions +namespace TestBO4E.Extensions; + +[TestClass] +public class TestEnergiemengeExtension { - [TestClass] - public class TestEnergiemengeExtension - { - internal static readonly TimeRange GERMAN_MARCH_2018 = - new TimeRange(new DateTime(2018, 2, 28, 23, 0, 0, DateTimeKind.Utc), - new DateTime(2018, 3, 31, 22, 0, 0, DateTimeKind.Utc)); + internal static readonly TimeRange GERMAN_MARCH_2018 = + new TimeRange(new DateTime(2018, 2, 28, 23, 0, 0, DateTimeKind.Utc), + new DateTime(2018, 3, 31, 22, 0, 0, DateTimeKind.Utc)); - internal static readonly TimeRange GERMAN_APRIL_2018 = - new TimeRange(new DateTime(2018, 3, 31, 22, 0, 0, DateTimeKind.Utc), - new DateTime(2018, 4, 30, 22, 0, 0, DateTimeKind.Utc)); + internal static readonly TimeRange GERMAN_APRIL_2018 = + new TimeRange(new DateTime(2018, 3, 31, 22, 0, 0, DateTimeKind.Utc), + new DateTime(2018, 4, 30, 22, 0, 0, DateTimeKind.Utc)); - internal static readonly TimeRange march2425 = - new TimeRange(new DateTime(2018, 3, 23, 23, 0, 0, DateTimeKind.Utc), - new DateTime(2018, 3, 25, 22, 0, 0, DateTimeKind.Utc)); + internal static readonly TimeRange march2425 = + new TimeRange(new DateTime(2018, 3, 23, 23, 0, 0, DateTimeKind.Utc), + new DateTime(2018, 3, 25, 22, 0, 0, DateTimeKind.Utc)); - [TestMethod] - public void TestTestingRanges() - { - Assert.AreEqual(30 * 24, GERMAN_APRIL_2018.Duration.TotalHours); // keine Zeitumstellung im April - Assert.AreEqual(31 * 24 - 1, GERMAN_MARCH_2018.Duration.TotalHours); // Uhren am 25.03.18 eine Stunde vor - Assert.AreEqual(47, march2425.Duration.TotalHours); - } + [TestMethod] + public void TestTestingRanges() + { + Assert.AreEqual(30 * 24, GERMAN_APRIL_2018.Duration.TotalHours); // keine Zeitumstellung im April + Assert.AreEqual(31 * 24 - 1, GERMAN_MARCH_2018.Duration.TotalHours); // Uhren am 25.03.18 eine Stunde vor + Assert.AreEqual(47, march2425.Duration.TotalHours); + } - [TestMethod] - public void TestDetangling() - { - var em = JsonConvert.DeserializeObject( - "{\"versionStruktur\":1,\"boTyp\":\"ENERGIEMENGE\",\"lokationsId\":\"DE0003604780400000000000012345678\",\"lokationstyp\":\"MeLo\",\"energieverbrauch\":[{\"startdatum\":\"2019-03-01T00:00:00Z\",\"enddatum\":\"2019-06-24T00:00:00Z\",\"wertermittlungsverfahren\":\"MESSUNG\",\"obiskennzahl\":\"1-0:1.8.0\",\"wert\":1,\"einheit\":\"KWH\",\"zaehlernummer\":\"10654212\"},{\"startdatum\":\"2019-03-01T00:00:00Z\",\"enddatum\":\"2019-06-24T00:00:00Z\",\"wertermittlungsverfahren\":\"MESSUNG\",\"obiskennzahl\":\"1-0:2.8.0\",\"wert\":1,\"einheit\":\"KWH\",\"zaehlernummer\":\"10654212\"}],\"anlagennummer\":\"50693510\",\"messlokationsId\":\"DE0003604780400000000000012345678\",\"marktlokationsId\":\"\",\"isMelo\":true,\"zaehlernummer\":\"10654212\"}"); - em.Detangle(); - Assert.AreEqual(2, em.Energieverbrauch.Count); - // todo: add real test. this one is limited. - } + [TestMethod] + public void TestDetangling() + { + var em = JsonConvert.DeserializeObject( + "{\"versionStruktur\":1,\"boTyp\":\"ENERGIEMENGE\",\"lokationsId\":\"DE0003604780400000000000012345678\",\"lokationstyp\":\"MeLo\",\"energieverbrauch\":[{\"startdatum\":\"2019-03-01T00:00:00Z\",\"enddatum\":\"2019-06-24T00:00:00Z\",\"wertermittlungsverfahren\":\"MESSUNG\",\"obiskennzahl\":\"1-0:1.8.0\",\"wert\":1,\"einheit\":\"KWH\",\"zaehlernummer\":\"10654212\"},{\"startdatum\":\"2019-03-01T00:00:00Z\",\"enddatum\":\"2019-06-24T00:00:00Z\",\"wertermittlungsverfahren\":\"MESSUNG\",\"obiskennzahl\":\"1-0:2.8.0\",\"wert\":1,\"einheit\":\"KWH\",\"zaehlernummer\":\"10654212\"}],\"anlagennummer\":\"50693510\",\"messlokationsId\":\"DE0003604780400000000000012345678\",\"marktlokationsId\":\"\",\"isMelo\":true,\"zaehlernummer\":\"10654212\"}"); + em.Detangle(); + Assert.AreEqual(2, em.Energieverbrauch.Count); + // todo: add real test. this one is limited. } -} +} \ No newline at end of file diff --git a/TestBO4E.Extensions/TestEnergiemengeExtensionCompleteness.cs b/TestBO4E.Extensions/TestEnergiemengeExtensionCompleteness.cs index d2236fc5..a1042f2d 100644 --- a/TestBO4E.Extensions/TestEnergiemengeExtensionCompleteness.cs +++ b/TestBO4E.Extensions/TestEnergiemengeExtensionCompleteness.cs @@ -18,385 +18,384 @@ using JsonSerializer = System.Text.Json.JsonSerializer; -namespace TestBO4E.Extensions +namespace TestBO4E.Extensions; + +[TestClass] +public class TestEnergiemengeExtensionCompleteness { - [TestClass] - public class TestEnergiemengeExtensionCompleteness - { - internal static readonly TimeRange CHRISTMAS_2018 = new TimeRange( - new DateTimeOffset(2018, 12, 23, 22, 0, 0, TimeSpan.Zero).UtcDateTime, - new DateTimeOffset(2018, 12, 31, 22, 0, 0, TimeSpan.Zero).UtcDateTime); + internal static readonly TimeRange CHRISTMAS_2018 = new TimeRange( + new DateTimeOffset(2018, 12, 23, 22, 0, 0, TimeSpan.Zero).UtcDateTime, + new DateTimeOffset(2018, 12, 31, 22, 0, 0, TimeSpan.Zero).UtcDateTime); - internal static readonly TimeRange GERMAN_YEAR_2018 = new TimeRange( - new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime, - new DateTimeOffset(2018, 12, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime); + internal static readonly TimeRange GERMAN_YEAR_2018 = new TimeRange( + new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime, + new DateTimeOffset(2018, 12, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime); - [TestMethod] - public void TestFirstLastGap() + [TestMethod] + public void TestFirstLastGap() + { + var em = new Energiemenge { - var em = new Energiemenge + LokationsId = "DE123455", + LokationsTyp = Lokationstyp.MELO, + Energieverbrauch = new List { - LokationsId = "DE123455", - LokationsTyp = Lokationstyp.MELO, - Energieverbrauch = new List + new Verbrauch + { + Obiskennzahl = "1234", + Wert = 123.456M, + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, + Startdatum = new DateTimeOffset(2019, 1, 1, 0, 0, 0, TimeSpan.Zero).UtcDateTime, + Enddatum = new DateTimeOffset(2019, 1, 4, 0, 0, 0, TimeSpan.Zero).UtcDateTime + }, + new Verbrauch { - new Verbrauch - { - Obiskennzahl = "1234", - Wert = 123.456M, - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, - Startdatum = new DateTimeOffset(2019, 1, 1, 0, 0, 0, TimeSpan.Zero).UtcDateTime, - Enddatum = new DateTimeOffset(2019, 1, 4, 0, 0, 0, TimeSpan.Zero).UtcDateTime - }, - new Verbrauch - { - Obiskennzahl = "1234", - Wert = 123.456M, - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, - Startdatum = new DateTimeOffset(2019, 1, 4, 0, 0, 0, TimeSpan.Zero).UtcDateTime, - Enddatum = new DateTimeOffset(2019, 1, 7, 0, 0, 0, TimeSpan.Zero).UtcDateTime - } + Obiskennzahl = "1234", + Wert = 123.456M, + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, + Startdatum = new DateTimeOffset(2019, 1, 4, 0, 0, 0, TimeSpan.Zero).UtcDateTime, + Enddatum = new DateTimeOffset(2019, 1, 7, 0, 0, 0, TimeSpan.Zero).UtcDateTime } - }; - - var cr = em.GetCompletenessReport(new TimeRange(new DateTime(2018, 12, 29, 0, 0, 0, DateTimeKind.Utc), - new DateTime(2019, 1, 10, 0, 0, 0, DateTimeKind.Utc))); - Assert.AreEqual(2, cr.Gaps.Count); - Assert.AreEqual(new DateTimeOffset(2018, 12, 29, 0, 0, 0, TimeSpan.Zero), cr.Gaps.First().Startdatum); - Assert.AreEqual(new DateTimeOffset(2019, 1, 1, 0, 0, 0, TimeSpan.Zero), cr.Gaps.First().Enddatum); - Assert.AreEqual(new DateTimeOffset(2019, 1, 7, 0, 0, 0, TimeSpan.Zero), cr.Gaps.Last().Startdatum); - Assert.AreEqual(new DateTimeOffset(2019, 1, 10, 0, 0, 0, TimeSpan.Zero), cr.Gaps.Last().Enddatum); - } + } + }; + + var cr = em.GetCompletenessReport(new TimeRange(new DateTime(2018, 12, 29, 0, 0, 0, DateTimeKind.Utc), + new DateTime(2019, 1, 10, 0, 0, 0, DateTimeKind.Utc))); + Assert.AreEqual(2, cr.Gaps.Count); + Assert.AreEqual(new DateTimeOffset(2018, 12, 29, 0, 0, 0, TimeSpan.Zero), cr.Gaps.First().Startdatum); + Assert.AreEqual(new DateTimeOffset(2019, 1, 1, 0, 0, 0, TimeSpan.Zero), cr.Gaps.First().Enddatum); + Assert.AreEqual(new DateTimeOffset(2019, 1, 7, 0, 0, 0, TimeSpan.Zero), cr.Gaps.Last().Startdatum); + Assert.AreEqual(new DateTimeOffset(2019, 1, 10, 0, 0, 0, TimeSpan.Zero), cr.Gaps.Last().Enddatum); + } - [TestMethod] - public void TestNullableCoverage() + [TestMethod] + public void TestNullableCoverage() + { + var em1 = new Energiemenge { - var em1 = new Energiemenge - { - LokationsId = "DE123456789DieseEmhatkeineVerbräuche", - LokationsTyp = Lokationstyp.MELO, - Energieverbrauch = new List() //empty list - }; - var cr1 = em1.GetCompletenessReport(); - Assert.IsNotNull(cr1); - Assert.IsNull(cr1.Coverage); - JsonConvert.SerializeObject(cr1); // must _not_ throw exception - - var em2 = new Energiemenge - { - LokationsId = "54321012345DieseEmhatkeineVerbräuche", - LokationsTyp = Lokationstyp.MELO, - Energieverbrauch = new List() //empty list - }; - var cr2 = em2.GetCompletenessReport(CHRISTMAS_2018, Wertermittlungsverfahren.MESSUNG, "1-2-3-4", - Mengeneinheit.KUBIKMETER); - Assert.IsNotNull(cr2); - Assert.IsNotNull(cr2.Coverage); // not null because no values but configuration given - Assert.AreEqual(0.0M, cr2.Coverage); - JsonConvert.SerializeObject(cr2); // must _not_ throw exception - - var cr3 = em2.GetCompletenessReport(CHRISTMAS_2018); - Assert.IsNotNull(cr3); - Assert.IsNotNull(cr3.Coverage); - Assert.AreEqual(0.0M, cr3.Coverage); - JsonConvert.SerializeObject(cr3); // must _not_ throw exception - } + LokationsId = "DE123456789DieseEmhatkeineVerbräuche", + LokationsTyp = Lokationstyp.MELO, + Energieverbrauch = new List() //empty list + }; + var cr1 = em1.GetCompletenessReport(); + Assert.IsNotNull(cr1); + Assert.IsNull(cr1.Coverage); + JsonConvert.SerializeObject(cr1); // must _not_ throw exception + + var em2 = new Energiemenge + { + LokationsId = "54321012345DieseEmhatkeineVerbräuche", + LokationsTyp = Lokationstyp.MELO, + Energieverbrauch = new List() //empty list + }; + var cr2 = em2.GetCompletenessReport(CHRISTMAS_2018, Wertermittlungsverfahren.MESSUNG, "1-2-3-4", + Mengeneinheit.KUBIKMETER); + Assert.IsNotNull(cr2); + Assert.IsNotNull(cr2.Coverage); // not null because no values but configuration given + Assert.AreEqual(0.0M, cr2.Coverage); + JsonConvert.SerializeObject(cr2); // must _not_ throw exception + + var cr3 = em2.GetCompletenessReport(CHRISTMAS_2018); + Assert.IsNotNull(cr3); + Assert.IsNotNull(cr3.Coverage); + Assert.AreEqual(0.0M, cr3.Coverage); + JsonConvert.SerializeObject(cr3); // must _not_ throw exception + } - [TestMethod] - public void TestDailyCompleteness() + [TestMethod] + public void TestDailyCompleteness() + { + foreach (var boFile in Directory.GetFiles("Energiemenge/completeness/", "50hz_prognose*.json")) { - foreach (var boFile in Directory.GetFiles("Energiemenge/completeness/", "50hz_prognose*.json")) + string jsonString; + using (var r = new StreamReader(boFile)) { - string jsonString; - using (var r = new StreamReader(boFile)) - { - jsonString = r.ReadToEnd(); - } - var em = JsonConvert.DeserializeObject(jsonString); - var result = em.GetDailyCompletenessReports(CHRISTMAS_2018); - Assert.AreEqual(8, result.Count); - break; // one test is enough. the rest is covered by the individual completeness report tests. + jsonString = r.ReadToEnd(); } + var em = JsonConvert.DeserializeObject(jsonString); + var result = em.GetDailyCompletenessReports(CHRISTMAS_2018); + Assert.AreEqual(8, result.Count); + break; // one test is enough. the rest is covered by the individual completeness report tests. } + } - [TestMethod] - [Obsolete] - public void TestMonthlySlices() - { - TestMonthlySlices(true); - } + [TestMethod] + [Obsolete] + public void TestMonthlySlices() + { + TestMonthlySlices(true); + } - [Obsolete] - internal void TestMonthlySlices(bool testFirstOnly = true, bool useParallelExecution = false) + [Obsolete] + internal void TestMonthlySlices(bool testFirstOnly = true, bool useParallelExecution = false) + { + foreach (var boFile in Directory.GetFiles("Energiemenge/completeness", "50hz_prognose*.json")) { - foreach (var boFile in Directory.GetFiles("Energiemenge/completeness", "50hz_prognose*.json")) + string jsonString; + using (var r = new StreamReader(boFile)) { - string jsonString; - using (var r = new StreamReader(boFile)) - { - jsonString = r.ReadToEnd(); - } - var em = JsonConvert.DeserializeObject(jsonString); - var result = em.GetMonthlyCompletenessReports(GERMAN_YEAR_2018, useParallelExecution); - Assert.AreEqual(12, - result.Count); // don't care about values of coverage, just the start/end and count of reports generated. - if (testFirstOnly) - { - break; // one test is enough. the rest is covered by the individual completeness report tests - } + jsonString = r.ReadToEnd(); + } + var em = JsonConvert.DeserializeObject(jsonString); + var result = em.GetMonthlyCompletenessReports(GERMAN_YEAR_2018, useParallelExecution); + Assert.AreEqual(12, + result.Count); // don't care about values of coverage, just the start/end and count of reports generated. + if (testFirstOnly) + { + break; // one test is enough. the rest is covered by the individual completeness report tests } } + } - [DoNotParallelize] - [TestMethod] - public void TestParallization() + [DoNotParallelize] + [TestMethod] + public void TestParallization() + { + for (var i = 0; i < 10; i++) { - for (var i = 0; i < 10; i++) + Energiemenge em; + using (var r = + new StreamReader(Directory.GetFiles("Energiemenge/completeness", "threeyears.json").First())) { - Energiemenge em; - using (var r = - new StreamReader(Directory.GetFiles("Energiemenge/completeness", "threeyears.json").First())) - { - var jsonString = r.ReadToEnd(); - em = JsonConvert.DeserializeObject(jsonString); - } + var jsonString = r.ReadToEnd(); + em = JsonConvert.DeserializeObject(jsonString); + } - em.GetMonthlyCompletenessReports(new TimeRange(new DateTime(2016, 1, 31, 23, 0, 0, DateTimeKind.Utc), - new DateTime(2016, 12, 31, 23, 0, 0, DateTimeKind.Utc))); + em.GetMonthlyCompletenessReports(new TimeRange(new DateTime(2016, 1, 31, 23, 0, 0, DateTimeKind.Utc), + new DateTime(2016, 12, 31, 23, 0, 0, DateTimeKind.Utc))); - em.GetMonthlyCompletenessReports( - new TimeRange(new DateTime(2016, 1, 31, 23, 0, 0, DateTimeKind.Utc), - new DateTime(2016, 12, 31, 23, 0, 0, DateTimeKind.Utc)), true); + em.GetMonthlyCompletenessReports( + new TimeRange(new DateTime(2016, 1, 31, 23, 0, 0, DateTimeKind.Utc), + new DateTime(2016, 12, 31, 23, 0, 0, DateTimeKind.Utc)), true); - //Assert.IsTrue(mpParallel.DurationMilliseconds < 3000, $"Parallel completeness report generation was too slow. Expected less than 3 seconds but was {mpParallel.DurationMilliseconds}ms: {mpParallel.RenderPlainText()}"); - //Assert.IsTrue(mpParallel.DurationMilliseconds < (int)mpLinear.DurationMilliseconds * 1.25M, $"Parallel: {mpParallel.DurationMilliseconds}, Non-Parallel: {mpLinear.DurationMilliseconds}"); - } - //int a = 0; + //Assert.IsTrue(mpParallel.DurationMilliseconds < 3000, $"Parallel completeness report generation was too slow. Expected less than 3 seconds but was {mpParallel.DurationMilliseconds}ms: {mpParallel.RenderPlainText()}"); + //Assert.IsTrue(mpParallel.DurationMilliseconds < (int)mpLinear.DurationMilliseconds * 1.25M, $"Parallel: {mpParallel.DurationMilliseconds}, Non-Parallel: {mpLinear.DurationMilliseconds}"); } + //int a = 0; + } - [DoNotParallelize] - [TestMethod] - public async Task TestParallizationSystemTextJson() + [DoNotParallelize] + [TestMethod] + public async Task TestParallizationSystemTextJson() + { + for (var i = 0; i < 10; i++) { - for (var i = 0; i < 10; i++) - { - Energiemenge em; - var r = Directory.GetFiles("Energiemenge/completeness", "threeyears.json").First(); - await using var openStream = File.OpenRead(r); - em = await JsonSerializer.DeserializeAsync(openStream, - LenientParsing.MOST_LENIENT.GetJsonSerializerOptions()); + Energiemenge em; + var r = Directory.GetFiles("Energiemenge/completeness", "threeyears.json").First(); + await using var openStream = File.OpenRead(r); + em = await JsonSerializer.DeserializeAsync(openStream, + LenientParsing.MOST_LENIENT.GetJsonSerializerOptions()); - em.GetMonthlyCompletenessReports(new TimeRange(new DateTime(2016, 1, 31, 23, 0, 0, DateTimeKind.Utc), - new DateTime(2016, 12, 31, 23, 0, 0, DateTimeKind.Utc))); + em.GetMonthlyCompletenessReports(new TimeRange(new DateTime(2016, 1, 31, 23, 0, 0, DateTimeKind.Utc), + new DateTime(2016, 12, 31, 23, 0, 0, DateTimeKind.Utc))); - em.GetMonthlyCompletenessReports( - new TimeRange(new DateTime(2016, 1, 31, 23, 0, 0, DateTimeKind.Utc), - new DateTime(2016, 12, 31, 23, 0, 0, DateTimeKind.Utc)), true); + em.GetMonthlyCompletenessReports( + new TimeRange(new DateTime(2016, 1, 31, 23, 0, 0, DateTimeKind.Utc), + new DateTime(2016, 12, 31, 23, 0, 0, DateTimeKind.Utc)), true); - //Assert.IsTrue(mpParallel.DurationMilliseconds < 3000, $"Parallel completeness report generation was too slow. Expected less than 3 seconds but was {mpParallel.DurationMilliseconds}ms: {mpParallel.RenderPlainText()}"); - //Assert.IsTrue(mpParallel.DurationMilliseconds < (int)mpLinear.DurationMilliseconds * 1.25M, $"Parallel: {mpParallel.DurationMilliseconds}, Non-Parallel: {mpLinear.DurationMilliseconds}"); - } + //Assert.IsTrue(mpParallel.DurationMilliseconds < 3000, $"Parallel completeness report generation was too slow. Expected less than 3 seconds but was {mpParallel.DurationMilliseconds}ms: {mpParallel.RenderPlainText()}"); + //Assert.IsTrue(mpParallel.DurationMilliseconds < (int)mpLinear.DurationMilliseconds * 1.25M, $"Parallel: {mpParallel.DurationMilliseconds}, Non-Parallel: {mpLinear.DurationMilliseconds}"); } - //int a = 0; + } + //int a = 0; - [TestMethod] - public void TestDailyParallization() + [TestMethod] + public void TestDailyParallization() + { + //Energiemenge em ; + //using (StreamReader r = new StreamReader(Directory.GetFiles("BusinessObjectExtensions/Energiemenge/completeness", "threeyears.json").First())) + //{ + // string jsonString = r.ReadToEnd(); + // em = JsonConvert.DeserializeObject(jsonString); + //} + var em = new Energiemenge(); + var dateTime = DateTime.Parse("2015-01-31 22:45:00"); + var listvb = new List(); + for (var u = 0; u < 1500; u++) { - //Energiemenge em ; - //using (StreamReader r = new StreamReader(Directory.GetFiles("BusinessObjectExtensions/Energiemenge/completeness", "threeyears.json").First())) - //{ - // string jsonString = r.ReadToEnd(); - // em = JsonConvert.DeserializeObject(jsonString); - //} - var em = new Energiemenge(); - var dateTime = DateTime.Parse("2015-01-31 22:45:00"); - var listvb = new List(); - for (var u = 0; u < 1500; u++) - { - dateTime = dateTime.AddMinutes(15); - var endDateTime = dateTime.AddMinutes(15); + dateTime = dateTime.AddMinutes(15); + var endDateTime = dateTime.AddMinutes(15); - listvb.Add(new Verbrauch - { Startdatum = dateTime, Enddatum = endDateTime, Einheit = Mengeneinheit.JAHR, Wert = 12 }); - dateTime = endDateTime; - } + listvb.Add(new Verbrauch + { Startdatum = dateTime, Enddatum = endDateTime, Einheit = Mengeneinheit.JAHR, Wert = 12 }); + dateTime = endDateTime; + } - em.Energieverbrauch = listvb; + em.Energieverbrauch = listvb; - em.GetMonthlyCompletenessReports(new TimeRange(new DateTime(2015, 1, 1, 23, 00, 0, DateTimeKind.Utc), - new DateTime(2019, 12, 31, 23, 0, 0, DateTimeKind.Utc))); + em.GetMonthlyCompletenessReports(new TimeRange(new DateTime(2015, 1, 1, 23, 00, 0, DateTimeKind.Utc), + new DateTime(2019, 12, 31, 23, 0, 0, DateTimeKind.Utc))); - //Assert.IsTrue(mpLinear.DurationMilliseconds < 4000, $"Linear completeness report generation was too slow. Expected less than 4 seconds but was {mpLinear.DurationMilliseconds}ms: {mpLinear.RenderPlainText()}"); + //Assert.IsTrue(mpLinear.DurationMilliseconds < 4000, $"Linear completeness report generation was too slow. Expected less than 4 seconds but was {mpLinear.DurationMilliseconds}ms: {mpLinear.RenderPlainText()}"); - em.GetDailyCompletenessReports( - new TimeRange(new DateTime(2015, 1, 01, 23, 0, 0, DateTimeKind.Utc), - new DateTime(2019, 12, 31, 23, 0, 0, DateTimeKind.Utc)), true); + em.GetDailyCompletenessReports( + new TimeRange(new DateTime(2015, 1, 01, 23, 0, 0, DateTimeKind.Utc), + new DateTime(2019, 12, 31, 23, 0, 0, DateTimeKind.Utc)), true); - //Assert.IsTrue(mpParallel.DurationMilliseconds < 3000, $"Parallel completeness report generation was too slow. Expected less than 3 seconds but was {mpParallel.DurationMilliseconds}ms: {mpParallel.RenderPlainText()}"); - //Assert.IsTrue(mpParallel.DurationMilliseconds < (int)mpLinear.DurationMilliseconds * 1.25M, $"Parallel: {mpParallel.DurationMilliseconds}, Non-Parallel: {mpLinear.DurationMilliseconds}"); - } + //Assert.IsTrue(mpParallel.DurationMilliseconds < 3000, $"Parallel completeness report generation was too slow. Expected less than 3 seconds but was {mpParallel.DurationMilliseconds}ms: {mpParallel.RenderPlainText()}"); + //Assert.IsTrue(mpParallel.DurationMilliseconds < (int)mpLinear.DurationMilliseconds * 1.25M, $"Parallel: {mpParallel.DurationMilliseconds}, Non-Parallel: {mpLinear.DurationMilliseconds}"); + } - [TestMethod] - public void TestDailyCompletenessDST() + [TestMethod] + public void TestDailyCompletenessDST() + { + var localStart = TimeZoneInfo.ConvertTimeFromUtc( + new DateTimeOffset(2018, 3, 24, 23, 0, 0, TimeSpan.Zero).UtcDateTime, + CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo); //, DateTimeKind.Unspecified); + var localEnd = TimeZoneInfo.ConvertTimeFromUtc( + new DateTimeOffset(2018, 3, 26, 22, 0, 0, TimeSpan.Zero).UtcDateTime, + CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo); //, DateTimeKind.Unspecified); + if (TimeZoneInfo.Local != CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo) { - var localStart = TimeZoneInfo.ConvertTimeFromUtc( - new DateTimeOffset(2018, 3, 24, 23, 0, 0, TimeSpan.Zero).UtcDateTime, - CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo); //, DateTimeKind.Unspecified); - var localEnd = TimeZoneInfo.ConvertTimeFromUtc( - new DateTimeOffset(2018, 3, 26, 22, 0, 0, TimeSpan.Zero).UtcDateTime, - CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo); //, DateTimeKind.Unspecified); - if (TimeZoneInfo.Local != CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo) - { - localStart = - DateTime.SpecifyKind( - TimeZoneInfo.ConvertTime(localStart, TimeZoneInfo.Local, - CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo), DateTimeKind.Unspecified); - localEnd = DateTime.SpecifyKind( - TimeZoneInfo.ConvertTime(localEnd, TimeZoneInfo.Local, + localStart = + DateTime.SpecifyKind( + TimeZoneInfo.ConvertTime(localStart, TimeZoneInfo.Local, CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo), DateTimeKind.Unspecified); - } - else - { - localStart = DateTime.SpecifyKind(localStart, DateTimeKind.Unspecified); - localEnd = DateTime.SpecifyKind(localEnd, DateTimeKind.Unspecified); - } + localEnd = DateTime.SpecifyKind( + TimeZoneInfo.ConvertTime(localEnd, TimeZoneInfo.Local, + CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo), DateTimeKind.Unspecified); + } + else + { + localStart = DateTime.SpecifyKind(localStart, DateTimeKind.Unspecified); + localEnd = DateTime.SpecifyKind(localEnd, DateTimeKind.Unspecified); + } - var utcStart = new DateTimeOffset(2018, 3, 24, 23, 0, 0, TimeSpan.Zero); - var utcEnd = new DateTimeOffset(2018, 3, 26, 22, 0, 0, TimeSpan.Zero); - if (TimeZoneInfo.Local.SupportsDaylightSavingTime && - CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo.Equals(TimeZoneInfo.Local)) - { - Assert.IsFalse( - CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo.IsDaylightSavingTime(localStart)); - Assert.IsTrue( - CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo.IsDaylightSavingTime(localEnd)); - } + var utcStart = new DateTimeOffset(2018, 3, 24, 23, 0, 0, TimeSpan.Zero); + var utcEnd = new DateTimeOffset(2018, 3, 26, 22, 0, 0, TimeSpan.Zero); + if (TimeZoneInfo.Local.SupportsDaylightSavingTime && + CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo.Equals(TimeZoneInfo.Local)) + { + Assert.IsFalse( + CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo.IsDaylightSavingTime(localStart)); + Assert.IsTrue( + CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo.IsDaylightSavingTime(localEnd)); + } - var verbrauchSlices = new List + var verbrauchSlices = new List + { + new TimeRange { - new TimeRange - { - Start = utcStart.UtcDateTime, - End = utcStart.AddHours(1).UtcDateTime - } - }; - while (verbrauchSlices.Last().End < utcEnd) - verbrauchSlices.Add(new TimeRange - { - Start = verbrauchSlices.Last().Start.AddHours(1), - End = verbrauchSlices.Last().End.AddHours(1) - }); - Assert.AreEqual(2 * 24 - 1, verbrauchSlices.Count); - var em = new Energiemenge + Start = utcStart.UtcDateTime, + End = utcStart.AddHours(1).UtcDateTime + } + }; + while (verbrauchSlices.Last().End < utcEnd) + verbrauchSlices.Add(new TimeRange { - LokationsId = "MeinUnitTest123", - LokationsTyp = Lokationstyp.MELO, - Energieverbrauch = verbrauchSlices.Select(vs => new Verbrauch - { - Startdatum = vs.Start, - Enddatum = vs.End, - Einheit = Mengeneinheit.KWH, - Wert = (decimal)123.456, - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG - } - ).ToList() - }; - var result = em.GetDailyCompletenessReports(new TimeRange(utcStart.UtcDateTime, utcEnd.UtcDateTime)); - Assert.AreEqual(2, result.Count); - Assert.AreEqual(new DateTimeOffset(2018, 3, 24, 23, 0, 0, TimeSpan.Zero), - result.First().Value.ReferenceTimeFrame.Startdatum); - Assert.AreEqual(new DateTimeOffset(2018, 3, 25, 22, 0, 0, TimeSpan.Zero), - result.First().Value.ReferenceTimeFrame.Enddatum); - Assert.AreEqual(new DateTimeOffset(2018, 3, 25, 22, 0, 0, TimeSpan.Zero), - result.Last().Value.ReferenceTimeFrame.Startdatum); - Assert.AreEqual(new DateTimeOffset(2018, 3, 26, 22, 0, 0, TimeSpan.Zero), - result.Last().Value.ReferenceTimeFrame.Enddatum); - } - - [TestMethod] - public void TestAddDaysDSTSpring() + Start = verbrauchSlices.Last().Start.AddHours(1), + End = verbrauchSlices.Last().End.AddHours(1) + }); + Assert.AreEqual(2 * 24 - 1, verbrauchSlices.Count); + var em = new Energiemenge { - var utcDt = new DateTimeOffset(2018, 3, 24, 23, 0, 0, TimeSpan.Zero).UtcDateTime; - var localDt = - DateTime.SpecifyKind( - TimeZoneInfo.ConvertTimeFromUtc( - new DateTimeOffset(2018, 3, 24, 23, 0, 0, TimeSpan.Zero).UtcDateTime, - CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo), DateTimeKind.Unspecified); + LokationsId = "MeinUnitTest123", + LokationsTyp = Lokationstyp.MELO, + Energieverbrauch = verbrauchSlices.Select(vs => new Verbrauch + { + Startdatum = vs.Start, + Enddatum = vs.End, + Einheit = Mengeneinheit.KWH, + Wert = (decimal)123.456, + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG + } + ).ToList() + }; + var result = em.GetDailyCompletenessReports(new TimeRange(utcStart.UtcDateTime, utcEnd.UtcDateTime)); + Assert.AreEqual(2, result.Count); + Assert.AreEqual(new DateTimeOffset(2018, 3, 24, 23, 0, 0, TimeSpan.Zero), + result.First().Value.ReferenceTimeFrame.Startdatum); + Assert.AreEqual(new DateTimeOffset(2018, 3, 25, 22, 0, 0, TimeSpan.Zero), + result.First().Value.ReferenceTimeFrame.Enddatum); + Assert.AreEqual(new DateTimeOffset(2018, 3, 25, 22, 0, 0, TimeSpan.Zero), + result.Last().Value.ReferenceTimeFrame.Startdatum); + Assert.AreEqual(new DateTimeOffset(2018, 3, 26, 22, 0, 0, TimeSpan.Zero), + result.Last().Value.ReferenceTimeFrame.Enddatum); + } - var resultUtc = utcDt.AddDaysDST(1); - var resultLocal = localDt.AddDaysDST(1); + [TestMethod] + public void TestAddDaysDSTSpring() + { + var utcDt = new DateTimeOffset(2018, 3, 24, 23, 0, 0, TimeSpan.Zero).UtcDateTime; + var localDt = + DateTime.SpecifyKind( + TimeZoneInfo.ConvertTimeFromUtc( + new DateTimeOffset(2018, 3, 24, 23, 0, 0, TimeSpan.Zero).UtcDateTime, + CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo), DateTimeKind.Unspecified); - Assert.AreEqual(DateTimeKind.Utc, resultUtc.Kind); - Assert.AreEqual(DateTimeKind.Unspecified, resultLocal.Kind); + var resultUtc = utcDt.AddDaysDST(1); + var resultLocal = localDt.AddDaysDST(1); - Assert.AreEqual(23, new TimeRange(utcDt, resultUtc).Duration.TotalHours); - Assert.AreEqual(23, new TimeRange - { - Start = TimeZoneInfo.ConvertTimeToUtc(DateTime.SpecifyKind(localDt, DateTimeKind.Unspecified), - CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo), - End = TimeZoneInfo.ConvertTimeToUtc(DateTime.SpecifyKind(resultLocal, DateTimeKind.Unspecified), - CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo) - }.Duration.TotalHours); - } + Assert.AreEqual(DateTimeKind.Utc, resultUtc.Kind); + Assert.AreEqual(DateTimeKind.Unspecified, resultLocal.Kind); - [TestMethod] - public void TestAddDaysDSTAutumn() + Assert.AreEqual(23, new TimeRange(utcDt, resultUtc).Duration.TotalHours); + Assert.AreEqual(23, new TimeRange { - var utcDt = new DateTimeOffset(2018, 10, 27, 22, 0, 0, TimeSpan.Zero).UtcDateTime; - var localDt = - DateTime.SpecifyKind( - TimeZoneInfo.ConvertTimeFromUtc( - new DateTimeOffset(2018, 10, 27, 22, 0, 0, TimeSpan.Zero).UtcDateTime, - CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo), DateTimeKind.Unspecified); + Start = TimeZoneInfo.ConvertTimeToUtc(DateTime.SpecifyKind(localDt, DateTimeKind.Unspecified), + CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo), + End = TimeZoneInfo.ConvertTimeToUtc(DateTime.SpecifyKind(resultLocal, DateTimeKind.Unspecified), + CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo) + }.Duration.TotalHours); + } - var resultUtc = utcDt.AddDaysDST(1); - var resultLocal = localDt.AddDaysDST(1); + [TestMethod] + public void TestAddDaysDSTAutumn() + { + var utcDt = new DateTimeOffset(2018, 10, 27, 22, 0, 0, TimeSpan.Zero).UtcDateTime; + var localDt = + DateTime.SpecifyKind( + TimeZoneInfo.ConvertTimeFromUtc( + new DateTimeOffset(2018, 10, 27, 22, 0, 0, TimeSpan.Zero).UtcDateTime, + CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo), DateTimeKind.Unspecified); - Assert.AreEqual(DateTimeKind.Utc, resultUtc.Kind); - Assert.AreEqual(DateTimeKind.Unspecified, resultLocal.Kind); + var resultUtc = utcDt.AddDaysDST(1); + var resultLocal = localDt.AddDaysDST(1); - Assert.AreEqual(25, new TimeRange(utcDt, resultUtc).Duration.TotalHours); - Assert.AreEqual(25, new TimeRange - { - Start = TimeZoneInfo.ConvertTimeToUtc(DateTime.SpecifyKind(localDt, DateTimeKind.Unspecified), - CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo), - End = TimeZoneInfo.ConvertTimeToUtc(DateTime.SpecifyKind(resultLocal, DateTimeKind.Unspecified), - CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo) - }.Duration.TotalHours); - } + Assert.AreEqual(DateTimeKind.Utc, resultUtc.Kind); + Assert.AreEqual(DateTimeKind.Unspecified, resultLocal.Kind); - [TestMethod] - public void TestAddDaysDSTSummer() // could be winter as well ;) + Assert.AreEqual(25, new TimeRange(utcDt, resultUtc).Duration.TotalHours); + Assert.AreEqual(25, new TimeRange { - var utcDt = new DateTimeOffset(2018, 7, 27, 22, 0, 0, TimeSpan.Zero).UtcDateTime; - var localDt = - DateTime.SpecifyKind( - TimeZoneInfo.ConvertTimeFromUtc( - new DateTimeOffset(2018, 7, 27, 22, 0, 0, TimeSpan.Zero).UtcDateTime, - CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo), DateTimeKind.Unspecified); + Start = TimeZoneInfo.ConvertTimeToUtc(DateTime.SpecifyKind(localDt, DateTimeKind.Unspecified), + CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo), + End = TimeZoneInfo.ConvertTimeToUtc(DateTime.SpecifyKind(resultLocal, DateTimeKind.Unspecified), + CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo) + }.Duration.TotalHours); + } - var resultUtc = utcDt.AddDaysDST(1); - var resultLocal = localDt.AddDaysDST(1); + [TestMethod] + public void TestAddDaysDSTSummer() // could be winter as well ;) + { + var utcDt = new DateTimeOffset(2018, 7, 27, 22, 0, 0, TimeSpan.Zero).UtcDateTime; + var localDt = + DateTime.SpecifyKind( + TimeZoneInfo.ConvertTimeFromUtc( + new DateTimeOffset(2018, 7, 27, 22, 0, 0, TimeSpan.Zero).UtcDateTime, + CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo), DateTimeKind.Unspecified); - Assert.AreEqual(DateTimeKind.Utc, resultUtc.Kind); - Assert.AreEqual(DateTimeKind.Unspecified, resultLocal.Kind); + var resultUtc = utcDt.AddDaysDST(1); + var resultLocal = localDt.AddDaysDST(1); - Assert.AreEqual(24, new TimeRange(utcDt, resultUtc).Duration.TotalHours); - Assert.AreEqual(24, new TimeRange - { - Start = TimeZoneInfo.ConvertTimeToUtc(DateTime.SpecifyKind(localDt, DateTimeKind.Unspecified), - CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo), - End = TimeZoneInfo.ConvertTimeToUtc(DateTime.SpecifyKind(resultLocal, DateTimeKind.Unspecified), - CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo) - }.Duration.TotalHours); - } + Assert.AreEqual(DateTimeKind.Utc, resultUtc.Kind); + Assert.AreEqual(DateTimeKind.Unspecified, resultLocal.Kind); + + Assert.AreEqual(24, new TimeRange(utcDt, resultUtc).Duration.TotalHours); + Assert.AreEqual(24, new TimeRange + { + Start = TimeZoneInfo.ConvertTimeToUtc(DateTime.SpecifyKind(localDt, DateTimeKind.Unspecified), + CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo), + End = TimeZoneInfo.ConvertTimeToUtc(DateTime.SpecifyKind(resultLocal, DateTimeKind.Unspecified), + CentralEuropeStandardTime.CentralEuropeStandardTimezoneInfo) + }.Duration.TotalHours); } -} +} \ No newline at end of file diff --git a/TestBO4E.Extensions/TestEnergiemengeExtensionPlausibility.cs b/TestBO4E.Extensions/TestEnergiemengeExtensionPlausibility.cs index 437880bc..c427261e 100644 --- a/TestBO4E.Extensions/TestEnergiemengeExtensionPlausibility.cs +++ b/TestBO4E.Extensions/TestEnergiemengeExtensionPlausibility.cs @@ -8,36 +8,35 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; -namespace TestBO4E.Extensions +namespace TestBO4E.Extensions; + +[TestClass] +public class TestEnergiemengeExtensionPlausibility { - [TestClass] - public class TestEnergiemengeExtensionPlausibility + [TestMethod] + public void TestPlausibilityReportGenerationSomeCustomer() { - [TestMethod] - public void TestPlausibilityReportGenerationSomeCustomer() + foreach (var boFile in Directory.GetFiles("Energiemenge/plausibility", "somecustomer*.json")) { - foreach (var boFile in Directory.GetFiles("Energiemenge/plausibility", "somecustomer*.json")) + JObject json; + using (var r = new StreamReader(boFile)) { - JObject json; - using (var r = new StreamReader(boFile)) + var jsonString = r.ReadToEnd(); + json = JsonConvert.DeserializeObject(jsonString); + } + + foreach (var key in new HashSet { "reference", "other", "expectedResult" }) + if (!json.ContainsKey(key)) { - var jsonString = r.ReadToEnd(); - json = JsonConvert.DeserializeObject(jsonString); + throw new ArgumentException($"Test file {boFile} has no key '{key}'."); } - foreach (var key in new HashSet { "reference", "other", "expectedResult" }) - if (!json.ContainsKey(key)) - { - throw new ArgumentException($"Test file {boFile} has no key '{key}'."); - } + var emReference = JsonConvert.DeserializeObject(json["reference"].ToString()); + var emOther = JsonConvert.DeserializeObject(json["other"].ToString()); - var emReference = JsonConvert.DeserializeObject(json["reference"].ToString()); - var emOther = JsonConvert.DeserializeObject(json["other"].ToString()); - - var prActual = emReference.GetPlausibilityReport(emOther); - var prExpected = JsonConvert.DeserializeObject(json["expectedResult"].ToString()); - //Assert.AreEqual(prExpected, prActual); - } + var prActual = emReference.GetPlausibilityReport(emOther); + var prExpected = JsonConvert.DeserializeObject(json["expectedResult"].ToString()); + //Assert.AreEqual(prExpected, prActual); } } } \ No newline at end of file diff --git a/TestBO4E.Extensions/TestMengeneinheitExtension.cs b/TestBO4E.Extensions/TestMengeneinheitExtension.cs index e513d9b6..2216ab4e 100644 --- a/TestBO4E.Extensions/TestMengeneinheitExtension.cs +++ b/TestBO4E.Extensions/TestMengeneinheitExtension.cs @@ -3,47 +3,46 @@ using BO4E.Extensions.ENUM; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace TestBO4E.Extensions +namespace TestBO4E.Extensions; + +[TestClass] +public class TestMengeneinheitExtension { - [TestClass] - public class TestMengeneinheitExtension + [TestMethod] + public void TestConvertibility() { - [TestMethod] - public void TestConvertibility() - { - Assert.IsTrue(Mengeneinheit.KW.IsConvertibleTo(Mengeneinheit.MW)); - Assert.IsTrue(Mengeneinheit.MW.IsConvertibleTo(Mengeneinheit.KW)); - Assert.IsTrue(Mengeneinheit.KWH.IsConvertibleTo(Mengeneinheit.MWH)); - Assert.IsFalse(Mengeneinheit.JAHR.IsConvertibleTo(Mengeneinheit.KUBIKMETER)); - } + Assert.IsTrue(Mengeneinheit.KW.IsConvertibleTo(Mengeneinheit.MW)); + Assert.IsTrue(Mengeneinheit.MW.IsConvertibleTo(Mengeneinheit.KW)); + Assert.IsTrue(Mengeneinheit.KWH.IsConvertibleTo(Mengeneinheit.MWH)); + Assert.IsFalse(Mengeneinheit.JAHR.IsConvertibleTo(Mengeneinheit.KUBIKMETER)); + } - [TestMethod] - public void TestConversionFactor() + [TestMethod] + public void TestConversionFactor() + { + foreach (Mengeneinheit me in Enum.GetValues(typeof(Mengeneinheit))) { - foreach (Mengeneinheit me in Enum.GetValues(typeof(Mengeneinheit))) + if ((int)me == 0) { - if ((int)me == 0) - { - continue; - } - - Assert.AreEqual(1.0M, me.GetConversionFactor(me)); - Assert.IsTrue(me.IsConvertibleTo(me)); + continue; } - Assert.AreEqual(1000.0M, Mengeneinheit.KWH.GetConversionFactor(Mengeneinheit.WH)); - Assert.AreEqual(1000.0M, Mengeneinheit.MWH.GetConversionFactor(Mengeneinheit.KWH)); - Assert.AreEqual(12.0M, Mengeneinheit.JAHR.GetConversionFactor(Mengeneinheit.MONAT)); - Assert.AreEqual(0.000001M, Mengeneinheit.WH.GetConversionFactor(Mengeneinheit.MWH)); - Assert.AreEqual(0.001M, Mengeneinheit.KW.GetConversionFactor(Mengeneinheit.MW)); - - foreach (Mengeneinheit me1 in Enum.GetValues(typeof(Mengeneinheit))) - foreach (Mengeneinheit me2 in Enum.GetValues(typeof(Mengeneinheit))) - if (!me1.IsConvertibleTo(me2)) - { - Assert.ThrowsException(() => me1.GetConversionFactor(me2), - $"Conversion {me1}-->{me2} should throw an exception!"); - } + Assert.AreEqual(1.0M, me.GetConversionFactor(me)); + Assert.IsTrue(me.IsConvertibleTo(me)); } + + Assert.AreEqual(1000.0M, Mengeneinheit.KWH.GetConversionFactor(Mengeneinheit.WH)); + Assert.AreEqual(1000.0M, Mengeneinheit.MWH.GetConversionFactor(Mengeneinheit.KWH)); + Assert.AreEqual(12.0M, Mengeneinheit.JAHR.GetConversionFactor(Mengeneinheit.MONAT)); + Assert.AreEqual(0.000001M, Mengeneinheit.WH.GetConversionFactor(Mengeneinheit.MWH)); + Assert.AreEqual(0.001M, Mengeneinheit.KW.GetConversionFactor(Mengeneinheit.MW)); + + foreach (Mengeneinheit me1 in Enum.GetValues(typeof(Mengeneinheit))) + foreach (Mengeneinheit me2 in Enum.GetValues(typeof(Mengeneinheit))) + if (!me1.IsConvertibleTo(me2)) + { + Assert.ThrowsException(() => me1.GetConversionFactor(me2), + $"Conversion {me1}-->{me2} should throw an exception!"); + } } } \ No newline at end of file diff --git a/TestBO4E.Extensions/TestVerbrauchExtension.cs b/TestBO4E.Extensions/TestVerbrauchExtension.cs index 46bd063a..619b4e2e 100644 --- a/TestBO4E.Extensions/TestVerbrauchExtension.cs +++ b/TestBO4E.Extensions/TestVerbrauchExtension.cs @@ -8,401 +8,400 @@ using Newtonsoft.Json; using static BO4E.Extensions.COM.VerbrauchExtension; -namespace TestBO4E.Extensions +namespace TestBO4E.Extensions; + +[TestClass] +public class TestVerbrauchExtension { - [TestClass] - public class TestVerbrauchExtension + private static readonly Verbrauch dtV1 = new Verbrauch + { + Obiskennzahl = "123", + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, + Einheit = Mengeneinheit.KWH, + Wert = 31 + 2 * 28, + Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero), + Enddatum = new DateTimeOffset(2018, 2, 28, 23, 0, 0, TimeSpan.Zero) + }; + + private static readonly Verbrauch dtV2 = new Verbrauch + { + Obiskennzahl = "123", + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, + Einheit = Mengeneinheit.KWH, + Wert = 31, + Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero), + Enddatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero) + }; + + private static readonly Verbrauch dtV3 = new Verbrauch + { + Obiskennzahl = "123", + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, + Einheit = Mengeneinheit.KWH, + Wert = 31 + 2 * 28 + 3 * 31, + Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero), + Enddatum = new DateTimeOffset(2018, 3, 31, 23, 0, 0, TimeSpan.Zero) + }; + + [TestMethod] + public void TestMergeNoOverlap() { - private static readonly Verbrauch dtV1 = new Verbrauch + var v1 = new Verbrauch { Obiskennzahl = "123", Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, Einheit = Mengeneinheit.KWH, - Wert = 31 + 2 * 28, + Wert = 5, Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero), - Enddatum = new DateTimeOffset(2018, 2, 28, 23, 0, 0, TimeSpan.Zero) + Enddatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero) + }; + var v2 = new Verbrauch + { + Obiskennzahl = "123", + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, + Einheit = Mengeneinheit.KWH, + Wert = 3, + Startdatum = new DateTimeOffset(2018, 2, 28, 23, 0, 0, TimeSpan.Zero), + Enddatum = new DateTimeOffset(2018, 3, 31, 23, 0, 0, TimeSpan.Zero) }; + var result = v1.Merge(v2); + Assert.AreEqual(2, result.Count); - private static readonly Verbrauch dtV2 = new Verbrauch + Assert.IsTrue(result.SetEquals(new HashSet { v1, v2 })); + } + + [TestMethod] + public void TestMergeAdjacentExtensive() + { + var v1 = new Verbrauch { Obiskennzahl = "123", Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, Einheit = Mengeneinheit.KWH, - Wert = 31, + Wert = 5, Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero), Enddatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero) }; - - private static readonly Verbrauch dtV3 = new Verbrauch + var v2 = new Verbrauch { Obiskennzahl = "123", Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, Einheit = Mengeneinheit.KWH, - Wert = 31 + 2 * 28 + 3 * 31, - Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero), - Enddatum = new DateTimeOffset(2018, 3, 31, 23, 0, 0, TimeSpan.Zero) + Wert = 3, + Startdatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero), + Enddatum = new DateTimeOffset(2018, 2, 28, 23, 0, 0, TimeSpan.Zero) }; + var result = v1.Merge(v2); + Assert.AreEqual(1, result.Count); + Assert.AreEqual(v1.Startdatum, result.First().Startdatum); + Assert.AreEqual(v2.Enddatum, result.First().Enddatum); + Assert.AreEqual(8, result.First().Wert); + } - [TestMethod] - public void TestMergeNoOverlap() + [TestMethod] + public void TestMergeAdjacentIntensive() + { + var v1 = new Verbrauch + { + Obiskennzahl = "123", + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, + Einheit = Mengeneinheit.KW, + Wert = 5, + Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero), + Enddatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero) + }; + var v2 = new Verbrauch { - var v1 = new Verbrauch - { - Obiskennzahl = "123", - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, - Einheit = Mengeneinheit.KWH, - Wert = 5, - Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero), - Enddatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero) - }; - var v2 = new Verbrauch - { - Obiskennzahl = "123", - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, - Einheit = Mengeneinheit.KWH, - Wert = 3, - Startdatum = new DateTimeOffset(2018, 2, 28, 23, 0, 0, TimeSpan.Zero), - Enddatum = new DateTimeOffset(2018, 3, 31, 23, 0, 0, TimeSpan.Zero) - }; - var result = v1.Merge(v2); - Assert.AreEqual(2, result.Count); + Obiskennzahl = "123", + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, + Einheit = Mengeneinheit.KW, + Wert = 3, + Startdatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero), + Enddatum = new DateTimeOffset(2018, 2, 28, 23, 0, 0, TimeSpan.Zero) + }; + var result12 = v1.Merge(v2); + Assert.AreEqual(2, result12.Count); - Assert.IsTrue(result.SetEquals(new HashSet { v1, v2 })); - } + Assert.IsTrue(result12.SetEquals(v2.Merge(v1))); - [TestMethod] - public void TestMergeAdjacentExtensive() + var v3 = new Verbrauch { - var v1 = new Verbrauch - { - Obiskennzahl = "123", - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, - Einheit = Mengeneinheit.KWH, - Wert = 5, - Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero), - Enddatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero) - }; - var v2 = new Verbrauch - { - Obiskennzahl = "123", - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, - Einheit = Mengeneinheit.KWH, - Wert = 3, - Startdatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero), - Enddatum = new DateTimeOffset(2018, 2, 28, 23, 0, 0, TimeSpan.Zero) - }; - var result = v1.Merge(v2); - Assert.AreEqual(1, result.Count); - Assert.AreEqual(v1.Startdatum, result.First().Startdatum); - Assert.AreEqual(v2.Enddatum, result.First().Enddatum); - Assert.AreEqual(8, result.First().Wert); - } - - [TestMethod] - public void TestMergeAdjacentIntensive() + Obiskennzahl = "123", + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, + Einheit = Mengeneinheit.KW, + Wert = 5, + Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero), + Enddatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero) + }; + var v4 = new Verbrauch { - var v1 = new Verbrauch - { - Obiskennzahl = "123", - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, - Einheit = Mengeneinheit.KW, - Wert = 5, - Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero), - Enddatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero) - }; - var v2 = new Verbrauch - { - Obiskennzahl = "123", - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, - Einheit = Mengeneinheit.KW, - Wert = 3, - Startdatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero), - Enddatum = new DateTimeOffset(2018, 2, 28, 23, 0, 0, TimeSpan.Zero) - }; - var result12 = v1.Merge(v2); - Assert.AreEqual(2, result12.Count); - - Assert.IsTrue(result12.SetEquals(v2.Merge(v1))); - - var v3 = new Verbrauch - { - Obiskennzahl = "123", - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, - Einheit = Mengeneinheit.KW, - Wert = 5, - Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero), - Enddatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero) - }; - var v4 = new Verbrauch - { - Obiskennzahl = "123", - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, - Einheit = Mengeneinheit.KW, - Wert = 5, - Startdatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero), - Enddatum = new DateTimeOffset(2018, 2, 28, 23, 0, 0, TimeSpan.Zero) - }; - } + Obiskennzahl = "123", + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, + Einheit = Mengeneinheit.KW, + Wert = 5, + Startdatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero), + Enddatum = new DateTimeOffset(2018, 2, 28, 23, 0, 0, TimeSpan.Zero) + }; + } - [TestMethod] - public void TestMergeOverlappingExtensive() + [TestMethod] + public void TestMergeOverlappingExtensive() + { + var v1 = new Verbrauch { - var v1 = new Verbrauch - { - Obiskennzahl = "123", - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, - Einheit = Mengeneinheit.KWH, - Wert = 5, - Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero), - Enddatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero) - }; - var v2 = new Verbrauch - { - Obiskennzahl = "123", - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, - Einheit = Mengeneinheit.KWH, - Wert = 3, - Startdatum = new DateTimeOffset(2018, 1, 15, 23, 0, 0, TimeSpan.Zero), - Enddatum = new DateTimeOffset(2018, 2, 28, 23, 0, 0, TimeSpan.Zero) - }; - var result = v1.Merge(v2); - Assert.AreEqual(1, result.Count); - Assert.AreEqual(v1.Startdatum, result.First().Startdatum); - Assert.AreEqual(v2.Enddatum, result.First().Enddatum); - Assert.AreEqual(8, result.First().Wert); - } + Obiskennzahl = "123", + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, + Einheit = Mengeneinheit.KWH, + Wert = 5, + Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero), + Enddatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero) + }; + var v2 = new Verbrauch + { + Obiskennzahl = "123", + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, + Einheit = Mengeneinheit.KWH, + Wert = 3, + Startdatum = new DateTimeOffset(2018, 1, 15, 23, 0, 0, TimeSpan.Zero), + Enddatum = new DateTimeOffset(2018, 2, 28, 23, 0, 0, TimeSpan.Zero) + }; + var result = v1.Merge(v2); + Assert.AreEqual(1, result.Count); + Assert.AreEqual(v1.Startdatum, result.First().Startdatum); + Assert.AreEqual(v2.Enddatum, result.First().Enddatum); + Assert.AreEqual(8, result.First().Wert); + } - [TestMethod] - public void TestMergeOverlappingIntensive() + [TestMethod] + public void TestMergeOverlappingIntensive() + { + var v1 = new Verbrauch + { + Obiskennzahl = "123", + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, + Einheit = Mengeneinheit.KW, + Wert = 5, + Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero), + Enddatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero) + }; + var v2 = new Verbrauch { - var v1 = new Verbrauch - { - Obiskennzahl = "123", - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, - Einheit = Mengeneinheit.KW, - Wert = 5, - Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero), - Enddatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero) - }; - var v2 = new Verbrauch - { - Obiskennzahl = "123", - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, - Einheit = Mengeneinheit.KW, - Wert = 3, - Startdatum = new DateTimeOffset(2018, 1, 15, 23, 0, 0, TimeSpan.Zero), - Enddatum = new DateTimeOffset(2018, 2, 28, 23, 0, 0, TimeSpan.Zero) - }; - var rawResult = v1.Merge(v2); - var result = new List(rawResult); - Assert.AreEqual(3, result.Count); - result.Sort(new VerbrauchDateTimeComparer()); - Assert.AreEqual(v1.Startdatum, result.First().Startdatum); - Assert.AreEqual(5, result.First().Wert); - Assert.AreEqual(v2.Startdatum, result[1].Startdatum); - Assert.AreEqual(v1.Enddatum, result[1].Enddatum); - Assert.AreEqual(8, result[1].Wert); - Assert.AreEqual(v2.Enddatum, result.Last().Enddatum); - Assert.AreEqual(3, result.Last().Wert); - } + Obiskennzahl = "123", + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, + Einheit = Mengeneinheit.KW, + Wert = 3, + Startdatum = new DateTimeOffset(2018, 1, 15, 23, 0, 0, TimeSpan.Zero), + Enddatum = new DateTimeOffset(2018, 2, 28, 23, 0, 0, TimeSpan.Zero) + }; + var rawResult = v1.Merge(v2); + var result = new List(rawResult); + Assert.AreEqual(3, result.Count); + result.Sort(new VerbrauchDateTimeComparer()); + Assert.AreEqual(v1.Startdatum, result.First().Startdatum); + Assert.AreEqual(5, result.First().Wert); + Assert.AreEqual(v2.Startdatum, result[1].Startdatum); + Assert.AreEqual(v1.Enddatum, result[1].Enddatum); + Assert.AreEqual(8, result[1].Wert); + Assert.AreEqual(v2.Enddatum, result.Last().Enddatum); + Assert.AreEqual(3, result.Last().Wert); + } - [TestMethod] - public void TestMergeRedundantIntensiveSameTime() + [TestMethod] + public void TestMergeRedundantIntensiveSameTime() + { + var v1 = new Verbrauch + { + Obiskennzahl = "123", + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, + Einheit = Mengeneinheit.KW, + Wert = 5, + Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime, + Enddatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime + }; + var v2 = new Verbrauch { - var v1 = new Verbrauch - { - Obiskennzahl = "123", - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, - Einheit = Mengeneinheit.KW, - Wert = 5, - Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime, - Enddatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime - }; - var v2 = new Verbrauch - { - Obiskennzahl = "123", - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, - Einheit = Mengeneinheit.KW, - Wert = 5, - Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime, - Enddatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime - }; - var rawResult = v1.MergeRedundant(v2, true); - var result = new List(rawResult); - Assert.AreEqual(1, result.Count); - v2.Should().BeEquivalentTo(v1, opts => opts.ComparingByMembers()); - v1.Should().BeEquivalentTo(result.First(), opts => opts.ComparingByMembers()); - Assert.AreEqual(5, result.First().Wert); - } + Obiskennzahl = "123", + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, + Einheit = Mengeneinheit.KW, + Wert = 5, + Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime, + Enddatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime + }; + var rawResult = v1.MergeRedundant(v2, true); + var result = new List(rawResult); + Assert.AreEqual(1, result.Count); + v2.Should().BeEquivalentTo(v1, opts => opts.ComparingByMembers()); + v1.Should().BeEquivalentTo(result.First(), opts => opts.ComparingByMembers()); + Assert.AreEqual(5, result.First().Wert); + } - [TestMethod] - public void TestMergeRedundantExtensiveSameTime() + [TestMethod] + public void TestMergeRedundantExtensiveSameTime() + { + var v1 = new Verbrauch { - var v1 = new Verbrauch - { - Obiskennzahl = "123", - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, - Einheit = Mengeneinheit.KWH, - Wert = 5, - Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime, - Enddatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime - }; - var v2 = new Verbrauch - { - Obiskennzahl = "123", - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, - Einheit = Mengeneinheit.KWH, - Wert = 5, - Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime, - Enddatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime - }; - var rawResult = v1.MergeRedundant(v2, true); - var result = new List(rawResult); - Assert.AreEqual(1, result.Count); - Assert.AreEqual(5, result.First().Wert); - } + Obiskennzahl = "123", + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, + Einheit = Mengeneinheit.KWH, + Wert = 5, + Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime, + Enddatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime + }; + var v2 = new Verbrauch + { + Obiskennzahl = "123", + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, + Einheit = Mengeneinheit.KWH, + Wert = 5, + Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime, + Enddatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime + }; + var rawResult = v1.MergeRedundant(v2, true); + var result = new List(rawResult); + Assert.AreEqual(1, result.Count); + Assert.AreEqual(5, result.First().Wert); + } - [TestMethod] - public void TestMergeRedundantExtensiveLeftJustifiedOverlap() + [TestMethod] + public void TestMergeRedundantExtensiveLeftJustifiedOverlap() + { + var v1 = new Verbrauch { - var v1 = new Verbrauch - { - Obiskennzahl = "123", - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, - Einheit = Mengeneinheit.KWH, - Wert = 5, - Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime, - Enddatum = new DateTimeOffset(2018, 2, 28, 23, 0, 0, TimeSpan.Zero).UtcDateTime - }; - var v2 = new Verbrauch - { - Obiskennzahl = "123", - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, - Einheit = Mengeneinheit.KWH, - Wert = 3, - Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime, - Enddatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime - }; - var rawResult = v1.MergeRedundant(v2, true); + Obiskennzahl = "123", + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, + Einheit = Mengeneinheit.KWH, + Wert = 5, + Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime, + Enddatum = new DateTimeOffset(2018, 2, 28, 23, 0, 0, TimeSpan.Zero).UtcDateTime + }; + var v2 = new Verbrauch + { + Obiskennzahl = "123", + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, + Einheit = Mengeneinheit.KWH, + Wert = 3, + Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime, + Enddatum = new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime + }; + var rawResult = v1.MergeRedundant(v2, true); - var result = new List(rawResult); - result.Sort(new VerbrauchDateTimeComparer()); - Assert.AreEqual(1, result.Count); + var result = new List(rawResult); + result.Sort(new VerbrauchDateTimeComparer()); + Assert.AreEqual(1, result.Count); - Assert.AreEqual(2, result.First().Wert); - Assert.AreEqual(new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero), result.First().Startdatum); - //Assert.AreEqual(new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero), result.First().enddatum); + Assert.AreEqual(2, result.First().Wert); + Assert.AreEqual(new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero), result.First().Startdatum); + //Assert.AreEqual(new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero), result.First().enddatum); - //Assert.AreEqual(5, result.Last().wert); - //Assert.AreEqual(new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero), result.Last().startdatum); - Assert.AreEqual(new DateTimeOffset(2018, 2, 28, 23, 0, 0, TimeSpan.Zero), result.Last().Enddatum); - } + //Assert.AreEqual(5, result.Last().wert); + //Assert.AreEqual(new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero), result.Last().startdatum); + Assert.AreEqual(new DateTimeOffset(2018, 2, 28, 23, 0, 0, TimeSpan.Zero), result.Last().Enddatum); + } - [TestMethod] - public void TestMergeRedundantRightJustifiedOverlap() - { - var v1 = JsonConvert.DeserializeObject( - "{\"startdatum\":\"2018-12-25T16:22:00Z\",\"enddatum\":\"2019-12-25T08:20:00Z\",\"wertermittlungsverfahren\":0,\"obiskennzahl\":\"1-1:1.8.0\",\"wert\":1539,\"einheit\":2,\"zaehlernummer\":\"10000548\"}"); - var v2 = JsonConvert.DeserializeObject( - "{\"startdatum\":\"2018-09-01T00:00:00Z\",\"enddatum\":\"2018-12-25T16:22:00Z\",\"wertermittlungsverfahren\":0,\"obiskennzahl\":\"1-1:1.8.0\",\"wert\":911,\"einheit\":2,\"zaehlernummer\":\"10000548\"}"); - var rawResult = v1.MergeRedundant(v2, true); - var result = new List(rawResult); - result.Sort(new VerbrauchDateTimeComparer()); - Assert.AreEqual(1, result.Count); + [TestMethod] + public void TestMergeRedundantRightJustifiedOverlap() + { + var v1 = JsonConvert.DeserializeObject( + "{\"startdatum\":\"2018-12-25T16:22:00Z\",\"enddatum\":\"2019-12-25T08:20:00Z\",\"wertermittlungsverfahren\":0,\"obiskennzahl\":\"1-1:1.8.0\",\"wert\":1539,\"einheit\":2,\"zaehlernummer\":\"10000548\"}"); + var v2 = JsonConvert.DeserializeObject( + "{\"startdatum\":\"2018-09-01T00:00:00Z\",\"enddatum\":\"2018-12-25T16:22:00Z\",\"wertermittlungsverfahren\":0,\"obiskennzahl\":\"1-1:1.8.0\",\"wert\":911,\"einheit\":2,\"zaehlernummer\":\"10000548\"}"); + var rawResult = v1.MergeRedundant(v2, true); + var result = new List(rawResult); + result.Sort(new VerbrauchDateTimeComparer()); + Assert.AreEqual(1, result.Count); - Assert.AreEqual(2450.0M, result.First().Wert); - Assert.AreEqual(new DateTimeOffset(2018, 9, 1, 0, 0, 0, TimeSpan.Zero), result.First().Startdatum); - Assert.AreEqual(new DateTimeOffset(2019, 12, 25, 08, 20, 0, TimeSpan.Zero), result.First().Enddatum); - } + Assert.AreEqual(2450.0M, result.First().Wert); + Assert.AreEqual(new DateTimeOffset(2018, 9, 1, 0, 0, 0, TimeSpan.Zero), result.First().Startdatum); + Assert.AreEqual(new DateTimeOffset(2019, 12, 25, 08, 20, 0, TimeSpan.Zero), result.First().Enddatum); + } - [TestMethod] - public void TestDetangleTwofold() - { - var result = Detangle(new List { dtV1, dtV2 }); - result.Sort(new VerbrauchDateTimeComparer()); - Assert.AreEqual(2, result.Count); - Assert.AreEqual(new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero), result.First().Startdatum); - Assert.AreEqual(new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero), result.First().Enddatum); - Assert.AreEqual(31, result.First().Wert); - Assert.AreEqual(new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero), result.Last().Startdatum); - Assert.AreEqual(new DateTimeOffset(2018, 2, 28, 23, 0, 0, TimeSpan.Zero), result.Last().Enddatum); - Assert.AreEqual(2 * 28, result.Last().Wert); - } + [TestMethod] + public void TestDetangleTwofold() + { + var result = Detangle(new List { dtV1, dtV2 }); + result.Sort(new VerbrauchDateTimeComparer()); + Assert.AreEqual(2, result.Count); + Assert.AreEqual(new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero), result.First().Startdatum); + Assert.AreEqual(new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero), result.First().Enddatum); + Assert.AreEqual(31, result.First().Wert); + Assert.AreEqual(new DateTimeOffset(2018, 1, 31, 23, 0, 0, TimeSpan.Zero), result.Last().Startdatum); + Assert.AreEqual(new DateTimeOffset(2018, 2, 28, 23, 0, 0, TimeSpan.Zero), result.Last().Enddatum); + Assert.AreEqual(2 * 28, result.Last().Wert); + } - [TestMethod] - public void TestDetangleThreefold() - { - var result = Detangle(new List { dtV1, dtV2, dtV3 }); - result.Sort(new VerbrauchDateTimeComparer()); - Assert.AreEqual(3, result.Count); - Assert.AreEqual(new DateTimeOffset(2017, 12, 31, 23, 0, 0, 0, TimeSpan.Zero), result[0].Startdatum); - Assert.AreEqual(new DateTimeOffset(2018, 1, 31, 23, 0, 0, 0, TimeSpan.Zero), result[0].Enddatum); - Assert.AreEqual(31, result[0].Wert); - Assert.AreEqual(new DateTimeOffset(2018, 1, 31, 23, 0, 0, 0, TimeSpan.Zero), result[1].Startdatum); - Assert.AreEqual(new DateTimeOffset(2018, 2, 28, 23, 0, 0, 0, TimeSpan.Zero), result[1].Enddatum); - Assert.AreEqual(2 * 28, result[1].Wert); - Assert.AreEqual(new DateTimeOffset(2018, 2, 28, 23, 0, 0, 0, TimeSpan.Zero), result[2].Startdatum); - Assert.AreEqual(new DateTimeOffset(2018, 3, 31, 23, 0, 0, 0, TimeSpan.Zero), result[2].Enddatum); - Assert.AreEqual(3 * 31, result[2].Wert); - } + [TestMethod] + public void TestDetangleThreefold() + { + var result = Detangle(new List { dtV1, dtV2, dtV3 }); + result.Sort(new VerbrauchDateTimeComparer()); + Assert.AreEqual(3, result.Count); + Assert.AreEqual(new DateTimeOffset(2017, 12, 31, 23, 0, 0, 0, TimeSpan.Zero), result[0].Startdatum); + Assert.AreEqual(new DateTimeOffset(2018, 1, 31, 23, 0, 0, 0, TimeSpan.Zero), result[0].Enddatum); + Assert.AreEqual(31, result[0].Wert); + Assert.AreEqual(new DateTimeOffset(2018, 1, 31, 23, 0, 0, 0, TimeSpan.Zero), result[1].Startdatum); + Assert.AreEqual(new DateTimeOffset(2018, 2, 28, 23, 0, 0, 0, TimeSpan.Zero), result[1].Enddatum); + Assert.AreEqual(2 * 28, result[1].Wert); + Assert.AreEqual(new DateTimeOffset(2018, 2, 28, 23, 0, 0, 0, TimeSpan.Zero), result[2].Startdatum); + Assert.AreEqual(new DateTimeOffset(2018, 3, 31, 23, 0, 0, 0, TimeSpan.Zero), result[2].Enddatum); + Assert.AreEqual(3 * 31, result[2].Wert); + } - [TestMethod] - public void TestHfSapDataDetangle() - { - var testList = JsonConvert.DeserializeObject>( - "[{\"startdatum\":\"2000-01-01T00:00:00Z\",\"enddatum\":\"2018-09-01T00:00:00Z\",\"wertermittlungsverfahren\":1,\"obiskennzahl\":\"1-1:1.8.0\",\"wert\":50,\"einheit\":2,\"zaehlernummer\":\"10000548\"},{\"startdatum\":\"2000-01-01T00:00:00Z\",\"enddatum\":\"2018-12-25T16:22:00Z\",\"wertermittlungsverfahren\":0,\"obiskennzahl\":\"1-1:1.8.0\",\"wert\":961,\"einheit\":2,\"zaehlernummer\":\"10000548\"},{\"startdatum\":\"2000-01-01T00:00:00Z\",\"enddatum\":\"2019-12-25T08:20:00Z\",\"wertermittlungsverfahren\":1,\"obiskennzahl\":\"1-1:1.8.0\",\"wert\":2500,\"einheit\":2,\"zaehlernummer\":\"10000548\"},{\"startdatum\":\"2018-09-01T00:00:00Z\",\"enddatum\":\"2018-12-25T16:22:00Z\",\"wertermittlungsverfahren\":0,\"obiskennzahl\":\"1-1:1.8.0\",\"wert\":911,\"einheit\":2,\"zaehlernummer\":\"10000548\"},{\"startdatum\":\"2018-09-01T00:00:00Z\",\"enddatum\":\"2019-12-25T08:20:00Z\",\"wertermittlungsverfahren\":1,\"obiskennzahl\":\"1-1:1.8.0\",\"wert\":2450,\"einheit\":2,\"zaehlernummer\":\"10000548\"},{\"startdatum\":\"2018-12-25T16:22:00Z\",\"enddatum\":\"2019-12-25T08:20:00Z\",\"wertermittlungsverfahren\":0,\"obiskennzahl\":\"1-1:1.8.0\",\"wert\":1539,\"einheit\":2,\"zaehlernummer\":\"10000548\"}]"); - Assert.AreEqual(3, testList.Count(v => v.Wertermittlungsverfahren == Wertermittlungsverfahren.MESSUNG)); - Assert.AreEqual(3, testList.Count(v => v.Wertermittlungsverfahren == Wertermittlungsverfahren.PROGNOSE)); - var result = Detangle(testList); - result.Sort(new VerbrauchDateTimeComparer()); - //Assert.AreEqual(5, result.Count); + [TestMethod] + public void TestHfSapDataDetangle() + { + var testList = JsonConvert.DeserializeObject>( + "[{\"startdatum\":\"2000-01-01T00:00:00Z\",\"enddatum\":\"2018-09-01T00:00:00Z\",\"wertermittlungsverfahren\":1,\"obiskennzahl\":\"1-1:1.8.0\",\"wert\":50,\"einheit\":2,\"zaehlernummer\":\"10000548\"},{\"startdatum\":\"2000-01-01T00:00:00Z\",\"enddatum\":\"2018-12-25T16:22:00Z\",\"wertermittlungsverfahren\":0,\"obiskennzahl\":\"1-1:1.8.0\",\"wert\":961,\"einheit\":2,\"zaehlernummer\":\"10000548\"},{\"startdatum\":\"2000-01-01T00:00:00Z\",\"enddatum\":\"2019-12-25T08:20:00Z\",\"wertermittlungsverfahren\":1,\"obiskennzahl\":\"1-1:1.8.0\",\"wert\":2500,\"einheit\":2,\"zaehlernummer\":\"10000548\"},{\"startdatum\":\"2018-09-01T00:00:00Z\",\"enddatum\":\"2018-12-25T16:22:00Z\",\"wertermittlungsverfahren\":0,\"obiskennzahl\":\"1-1:1.8.0\",\"wert\":911,\"einheit\":2,\"zaehlernummer\":\"10000548\"},{\"startdatum\":\"2018-09-01T00:00:00Z\",\"enddatum\":\"2019-12-25T08:20:00Z\",\"wertermittlungsverfahren\":1,\"obiskennzahl\":\"1-1:1.8.0\",\"wert\":2450,\"einheit\":2,\"zaehlernummer\":\"10000548\"},{\"startdatum\":\"2018-12-25T16:22:00Z\",\"enddatum\":\"2019-12-25T08:20:00Z\",\"wertermittlungsverfahren\":0,\"obiskennzahl\":\"1-1:1.8.0\",\"wert\":1539,\"einheit\":2,\"zaehlernummer\":\"10000548\"}]"); + Assert.AreEqual(3, testList.Count(v => v.Wertermittlungsverfahren == Wertermittlungsverfahren.MESSUNG)); + Assert.AreEqual(3, testList.Count(v => v.Wertermittlungsverfahren == Wertermittlungsverfahren.PROGNOSE)); + var result = Detangle(testList); + result.Sort(new VerbrauchDateTimeComparer()); + //Assert.AreEqual(5, result.Count); - var subResultMessung = result.Where(v => v.Wertermittlungsverfahren == Wertermittlungsverfahren.MESSUNG) - .ToList(); - Assert.AreEqual(2, subResultMessung.Count); + var subResultMessung = result.Where(v => v.Wertermittlungsverfahren == Wertermittlungsverfahren.MESSUNG) + .ToList(); + Assert.AreEqual(2, subResultMessung.Count); - Assert.AreEqual(new DateTimeOffset(2000, 1, 1, 0, 0, 0, TimeSpan.Zero), subResultMessung[0].Startdatum); - Assert.AreEqual(new DateTimeOffset(2018, 9, 1, 0, 0, 0, TimeSpan.Zero), subResultMessung[0].Enddatum); - Assert.AreEqual(50, subResultMessung[0].Wert); - Assert.AreEqual(new DateTimeOffset(2018, 9, 1, 0, 0, 0, TimeSpan.Zero), subResultMessung[1].Startdatum); - Assert.AreEqual(new DateTimeOffset(2019, 12, 25, 8, 20, 0, TimeSpan.Zero), subResultMessung[1].Enddatum); - Assert.AreEqual(2450, subResultMessung[1].Wert); + Assert.AreEqual(new DateTimeOffset(2000, 1, 1, 0, 0, 0, TimeSpan.Zero), subResultMessung[0].Startdatum); + Assert.AreEqual(new DateTimeOffset(2018, 9, 1, 0, 0, 0, TimeSpan.Zero), subResultMessung[0].Enddatum); + Assert.AreEqual(50, subResultMessung[0].Wert); + Assert.AreEqual(new DateTimeOffset(2018, 9, 1, 0, 0, 0, TimeSpan.Zero), subResultMessung[1].Startdatum); + Assert.AreEqual(new DateTimeOffset(2019, 12, 25, 8, 20, 0, TimeSpan.Zero), subResultMessung[1].Enddatum); + Assert.AreEqual(2450, subResultMessung[1].Wert); - var subResultPrognose = result.Where(v => v.Wertermittlungsverfahren == Wertermittlungsverfahren.PROGNOSE) - .ToList(); - Assert.AreEqual(3, subResultPrognose.Count); - Assert.AreEqual(new DateTimeOffset(2000, 1, 1, 0, 0, 0, TimeSpan.Zero), subResultPrognose[0].Startdatum); - Assert.AreEqual(new DateTimeOffset(2018, 9, 1, 0, 0, 0, TimeSpan.Zero), subResultPrognose[0].Enddatum); - Assert.AreEqual(50, subResultPrognose[0].Wert); - Assert.AreEqual(new DateTimeOffset(2018, 9, 1, 0, 0, 0, TimeSpan.Zero), subResultPrognose[1].Startdatum); - Assert.AreEqual(new DateTimeOffset(2018, 12, 25, 16, 22, 0, TimeSpan.Zero), subResultPrognose[1].Enddatum); - Assert.AreEqual(911, subResultPrognose[1].Wert); - Assert.AreEqual(new DateTimeOffset(2018, 12, 25, 16, 22, 0, TimeSpan.Zero), - subResultPrognose[2].Startdatum); - Assert.AreEqual(new DateTimeOffset(2019, 12, 25, 8, 20, 0, TimeSpan.Zero), subResultPrognose[2].Enddatum); - Assert.AreEqual(1539, subResultPrognose[2].Wert); - } + var subResultPrognose = result.Where(v => v.Wertermittlungsverfahren == Wertermittlungsverfahren.PROGNOSE) + .ToList(); + Assert.AreEqual(3, subResultPrognose.Count); + Assert.AreEqual(new DateTimeOffset(2000, 1, 1, 0, 0, 0, TimeSpan.Zero), subResultPrognose[0].Startdatum); + Assert.AreEqual(new DateTimeOffset(2018, 9, 1, 0, 0, 0, TimeSpan.Zero), subResultPrognose[0].Enddatum); + Assert.AreEqual(50, subResultPrognose[0].Wert); + Assert.AreEqual(new DateTimeOffset(2018, 9, 1, 0, 0, 0, TimeSpan.Zero), subResultPrognose[1].Startdatum); + Assert.AreEqual(new DateTimeOffset(2018, 12, 25, 16, 22, 0, TimeSpan.Zero), subResultPrognose[1].Enddatum); + Assert.AreEqual(911, subResultPrognose[1].Wert); + Assert.AreEqual(new DateTimeOffset(2018, 12, 25, 16, 22, 0, TimeSpan.Zero), + subResultPrognose[2].Startdatum); + Assert.AreEqual(new DateTimeOffset(2019, 12, 25, 8, 20, 0, TimeSpan.Zero), subResultPrognose[2].Enddatum); + Assert.AreEqual(1539, subResultPrognose[2].Wert); + } - [TestMethod] - public void TestUnitConversion() + [TestMethod] + public void TestUnitConversion() + { + var v1 = new Verbrauch { - var v1 = new Verbrauch - { - Obiskennzahl = "123", - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, - Einheit = Mengeneinheit.MW, - Wert = 17, - Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime, - Enddatum = new DateTimeOffset(2018, 3, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime - }; - v1.ConvertToUnit(Mengeneinheit.KW); - Assert.AreEqual(Mengeneinheit.KW, v1.Einheit); - Assert.AreEqual(17000.0M, v1.Wert); + Obiskennzahl = "123", + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG, + Einheit = Mengeneinheit.MW, + Wert = 17, + Startdatum = new DateTimeOffset(2017, 12, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime, + Enddatum = new DateTimeOffset(2018, 3, 31, 23, 0, 0, TimeSpan.Zero).UtcDateTime + }; + v1.ConvertToUnit(Mengeneinheit.KW); + Assert.AreEqual(Mengeneinheit.KW, v1.Einheit); + Assert.AreEqual(17000.0M, v1.Wert); - Assert.ThrowsException(() => v1.ConvertToUnit(Mengeneinheit.KWH)); - } + Assert.ThrowsException(() => v1.ConvertToUnit(Mengeneinheit.KWH)); } -} +} \ No newline at end of file diff --git a/TestBO4E.Reporting/ShowCaseTests/CompletenessReportShowCaseTests.cs b/TestBO4E.Reporting/ShowCaseTests/CompletenessReportShowCaseTests.cs index b01cecfa..978d170c 100644 --- a/TestBO4E.Reporting/ShowCaseTests/CompletenessReportShowCaseTests.cs +++ b/TestBO4E.Reporting/ShowCaseTests/CompletenessReportShowCaseTests.cs @@ -8,46 +8,45 @@ using BO4E.Extensions.BusinessObjects.Energiemenge; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace TestBO4E.Reporting.ShowCaseTests +namespace TestBO4E.Reporting.ShowCaseTests; + +[TestClass] +public class CompletenessReportShowCaseTests { - [TestClass] - public class CompletenessReportShowCaseTests + [TestMethod] + public void ShowCaseTest() { - [TestMethod] - public void ShowCaseTest() + var em = new Energiemenge { - var em = new Energiemenge + LokationsId = "DE0123456789012345678901234567890", + LokationsTyp = Lokationstyp.MELO, + Energieverbrauch = new List { - LokationsId = "DE0123456789012345678901234567890", - LokationsTyp = Lokationstyp.MELO, - Energieverbrauch = new List + new Verbrauch + { + Einheit = Mengeneinheit.KWH, + Startdatum = new DateTimeOffset(2020, 3, 1, 0, 0, 0, TimeSpan.Zero).UtcDateTime, + Enddatum = new DateTimeOffset(2020, 3, 8, 0, 0, 0, TimeSpan.Zero).UtcDateTime, + Wert = 456.0M, + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG + }, + new Verbrauch { - new Verbrauch - { - Einheit = Mengeneinheit.KWH, - Startdatum = new DateTimeOffset(2020, 3, 1, 0, 0, 0, TimeSpan.Zero).UtcDateTime, - Enddatum = new DateTimeOffset(2020, 3, 8, 0, 0, 0, TimeSpan.Zero).UtcDateTime, - Wert = 456.0M, - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG - }, - new Verbrauch - { - Einheit = Mengeneinheit.KWH, - Startdatum = new DateTimeOffset(2020, 3, 25, 0, 0, 0, TimeSpan.Zero).UtcDateTime, - Enddatum = new DateTimeOffset(2020, 4, 1, 0, 0, 0, TimeSpan.Zero).UtcDateTime, - Wert = 123.0M, - Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG - } + Einheit = Mengeneinheit.KWH, + Startdatum = new DateTimeOffset(2020, 3, 25, 0, 0, 0, TimeSpan.Zero).UtcDateTime, + Enddatum = new DateTimeOffset(2020, 4, 1, 0, 0, 0, TimeSpan.Zero).UtcDateTime, + Wert = 123.0M, + Wertermittlungsverfahren = Wertermittlungsverfahren.MESSUNG } - }; + } + }; - var cr = em.GetCompletenessReport(); - Debug.WriteLine($"{nameof(em)} has a coverage of {decimal.Round(cr.Coverage.Value * 100.0M)}%."); - // em has a coverage of 45%. + var cr = em.GetCompletenessReport(); + Debug.WriteLine($"{nameof(em)} has a coverage of {decimal.Round(cr.Coverage.Value * 100.0M)}%."); + // em has a coverage of 45%. - Debug.WriteLine( - $"{nameof(em)} has no values for the following intervals: {string.Join(", ", cr.Gaps.Select(g => g.Startdatum.ToString("yyyy-MM-dd") + " to " + g.Enddatum.ToString("yyyy-MM-dd")))}"); - // em has no values for the following intervals: 2020-03-08 to 2020-03-25 - } + Debug.WriteLine( + $"{nameof(em)} has no values for the following intervals: {string.Join(", ", cr.Gaps.Select(g => g.Startdatum.ToString("yyyy-MM-dd") + " to " + g.Enddatum.ToString("yyyy-MM-dd")))}"); + // em has no values for the following intervals: 2020-03-08 to 2020-03-25 } } \ No newline at end of file diff --git a/TestBO4E.Reporting/TestCompletenessReportSorting.cs b/TestBO4E.Reporting/TestCompletenessReportSorting.cs index 481b9fb0..0f6a935c 100644 --- a/TestBO4E.Reporting/TestCompletenessReportSorting.cs +++ b/TestBO4E.Reporting/TestCompletenessReportSorting.cs @@ -5,60 +5,59 @@ using BO4E.Reporting; using Microsoft.VisualStudio.TestTools.UnitTesting; -namespace TestBO4E.Reporting +namespace TestBO4E.Reporting; + +[TestClass] +public class TestCompletenessReportSorting { - [TestClass] - public class TestCompletenessReportSorting + [TestMethod] + public void TestStartdatumSorting() { - [TestMethod] - public void TestStartdatumSorting() + var cr1 = new CompletenessReport { - var cr1 = new CompletenessReport + ReferenceTimeFrame = new Zeitraum { - ReferenceTimeFrame = new Zeitraum - { - Startdatum = new DateTime(2001, 1, 1, 0, 0, 0, DateTimeKind.Utc) - } - }; - var cr2 = new CompletenessReport + Startdatum = new DateTime(2001, 1, 1, 0, 0, 0, DateTimeKind.Utc) + } + }; + var cr2 = new CompletenessReport + { + ReferenceTimeFrame = new Zeitraum { - ReferenceTimeFrame = new Zeitraum - { - Startdatum = new DateTime(2002, 1, 1, 0, 0, 0, DateTimeKind.Utc) - } - }; - var cr3 = new CompletenessReport + Startdatum = new DateTime(2002, 1, 1, 0, 0, 0, DateTimeKind.Utc) + } + }; + var cr3 = new CompletenessReport + { + ReferenceTimeFrame = new Zeitraum { - ReferenceTimeFrame = new Zeitraum - { - Startdatum = new DateTime(2003, 1, 1, 0, 0, 0, DateTimeKind.Utc) - } - }; - var crList = new List { cr2, cr3, cr1 }; - // before sorting - Assert.AreEqual(2002, crList.First().ReferenceTimeFrame.Startdatum.Value.Year); - Assert.AreEqual(2003, crList[1].ReferenceTimeFrame.Startdatum.Value.Year); - Assert.AreEqual(2001, crList.Last().ReferenceTimeFrame.Startdatum.Value.Year); + Startdatum = new DateTime(2003, 1, 1, 0, 0, 0, DateTimeKind.Utc) + } + }; + var crList = new List { cr2, cr3, cr1 }; + // before sorting + Assert.AreEqual(2002, crList.First().ReferenceTimeFrame.Startdatum.Value.Year); + Assert.AreEqual(2003, crList[1].ReferenceTimeFrame.Startdatum.Value.Year); + Assert.AreEqual(2001, crList.Last().ReferenceTimeFrame.Startdatum.Value.Year); - crList.Sort(); - //after sorting - Assert.AreEqual(2001, crList.First().ReferenceTimeFrame.Startdatum.Value.Year); - Assert.AreEqual(2002, crList[1].ReferenceTimeFrame.Startdatum.Value.Year); - Assert.AreEqual(2003, crList.Last().ReferenceTimeFrame.Startdatum.Value.Year); + crList.Sort(); + //after sorting + Assert.AreEqual(2001, crList.First().ReferenceTimeFrame.Startdatum.Value.Year); + Assert.AreEqual(2002, crList[1].ReferenceTimeFrame.Startdatum.Value.Year); + Assert.AreEqual(2003, crList.Last().ReferenceTimeFrame.Startdatum.Value.Year); - var crNull = new CompletenessReport(); - crList.Add(crNull); - var cr0 = new CompletenessReport + var crNull = new CompletenessReport(); + crList.Add(crNull); + var cr0 = new CompletenessReport + { + ReferenceTimeFrame = new Zeitraum { - ReferenceTimeFrame = new Zeitraum - { - Startdatum = new DateTime(1999, 1, 1, 0, 0, 0, DateTimeKind.Utc) - } - }; - crList.Add(cr0); - crList.Sort(); - Assert.IsNull(crList.First().ReferenceTimeFrame); - Assert.AreEqual(1999, crList[1].ReferenceTimeFrame.Startdatum.Value.Year); - } + Startdatum = new DateTime(1999, 1, 1, 0, 0, 0, DateTimeKind.Utc) + } + }; + crList.Add(cr0); + crList.Sort(); + Assert.IsNull(crList.First().ReferenceTimeFrame); + Assert.AreEqual(1999, crList[1].ReferenceTimeFrame.Startdatum.Value.Year); } } \ No newline at end of file diff --git a/TestBO4E.Reporting/TestReportToCsv.cs b/TestBO4E.Reporting/TestReportToCsv.cs index 723f7c72..6921612d 100644 --- a/TestBO4E.Reporting/TestReportToCsv.cs +++ b/TestBO4E.Reporting/TestReportToCsv.cs @@ -9,302 +9,301 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json; -namespace TestBO4E.Reporting +namespace TestBO4E.Reporting; + +[TestClass] +public class TestReportToCsv { - [TestClass] - public class TestReportToCsv + [TestMethod] + public void TestCompletenessReportToCsv() { - [TestMethod] - public void TestCompletenessReportToCsv() + var cr = new CompletenessReport { - var cr = new CompletenessReport - { - LokationsId = "DE12345", - Coverage = 0.87M, // 87% - Wertermittlungsverfahren = Wertermittlungsverfahren.PROGNOSE, - ReferenceTimeFrame = new Zeitraum - { - Startdatum = new DateTimeOffset(2019, 1, 1, 0, 0, 0, TimeSpan.Zero), - Enddatum = new DateTimeOffset(2019, 3, 1, 0, 0, 0, TimeSpan.Zero) - } - }; - var result = cr.ToCsv(';', true, Environment.NewLine); - var lines = new List(result.Split(Environment.NewLine)); - Assert.AreEqual(2, lines.Count); - - // reihenfolge - var reihenfolge = new List> - { - new Dictionary {["LokationsId"] = "messlokationsId"}, - new Dictionary {["Coverage"] = "Newcoverage"}, - new Dictionary {["Zeitraum.Startdatum"] = "time.startdatum"}, - new Dictionary {["Zeitraum.Enddatum"] = "time.enddatum"} - }; - - //string JSONdata = "{'completenessZfa':[{'lokationsId':'lokationsId'},{'coverage':'coverage'},{'Zeitraum.einheit':'einheit'},{'Zeitraum.dauer':'dauer'},{'Zeitraum.startdatum':'startdatum'},{'Zeitraum.enddatum':'enddatum'},{'obiskennzahl':'obiskennzahl'},{'einheit':'einheit'},{'wertermittlungsverfahren':'wertermittlungsverfahren'},{'startdatum':'Verbrauch.startdatum'},{'enddatum':'Verbrauch.enddatum'},{'wert':'Verbrauch.wert'},{'headerLine':'1'}]}"; - //var alldata = JsonConvert.DeserializeObject>>>(JSONdata); - //List> reihenfolge = alldata["completenessZfa"]; - - var newresult = cr.ToCsv(';', true, Environment.NewLine, reihenfolge); - lines = new List(newresult.Split(Environment.NewLine)); - Assert.AreEqual(2, lines.Count); - var decimalSeparator = Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator; - Assert.AreEqual("DE12345;0" + decimalSeparator + "87;2019-01-01T00:00:00Z;2019-03-01T00:00:00Z;", lines[1]); - var commaResult = cr.ToCsv(',', lineTerminator: Environment.NewLine, reihenfolge: reihenfolge); - var separator = ""; - if (decimalSeparator == ",") + LokationsId = "DE12345", + Coverage = 0.87M, // 87% + Wertermittlungsverfahren = Wertermittlungsverfahren.PROGNOSE, + ReferenceTimeFrame = new Zeitraum { - separator = "\""; + Startdatum = new DateTimeOffset(2019, 1, 1, 0, 0, 0, TimeSpan.Zero), + Enddatum = new DateTimeOffset(2019, 3, 1, 0, 0, 0, TimeSpan.Zero) } + }; + var result = cr.ToCsv(';', true, Environment.NewLine); + var lines = new List(result.Split(Environment.NewLine)); + Assert.AreEqual(2, lines.Count); - Assert.AreEqual( - $"DE12345,{separator}0" + decimalSeparator + - $"87{separator},2019-01-01T00:00:00Z,2019-03-01T00:00:00Z,", commaResult.Split(Environment.NewLine)[1]); - var dpunktResult = cr.ToCsv(':', lineTerminator: Environment.NewLine, reihenfolge: reihenfolge); - Assert.AreEqual("DE12345:0" + decimalSeparator + "87:\"2019-01-01T00:00:00Z\":\"2019-03-01T00:00:00Z\":", - dpunktResult.Split(Environment.NewLine)[1]); - - cr.Values = new List - { - new CompletenessReport.BasicVerbrauch - { - Wert = 17, - Startdatum = new DateTimeOffset(2019, 1, 1, 0, 0, 0, TimeSpan.Zero).UtcDateTime, - Enddatum = new DateTimeOffset(2019, 1, 2, 0, 0, 0, TimeSpan.Zero).UtcDateTime - }, - new CompletenessReport.BasicVerbrauch - { - Wert = 21, - Startdatum = new DateTimeOffset(2019, 1, 7, 0, 0, 0, TimeSpan.Zero).UtcDateTime, - Enddatum = new DateTimeOffset(2019, 1, 8, 0, 0, 0, TimeSpan.Zero).UtcDateTime - }, - new CompletenessReport.BasicVerbrauch - { - Wert = 35, - Startdatum = new DateTimeOffset(2019, 1, 12, 0, 0, 0, TimeSpan.Zero).UtcDateTime, - Enddatum = new DateTimeOffset(2019, 1, 13, 0, 0, 0, TimeSpan.Zero).UtcDateTime - } - }; - - reihenfolge.Add(new Dictionary { ["Wert"] = "V.wert" }); - reihenfolge.Add(new Dictionary { ["Startdatum"] = "V.startdatum" }); - reihenfolge.Add(new Dictionary { ["Enddatum"] = "V.enddatum" }); + // reihenfolge + var reihenfolge = new List> + { + new Dictionary {["LokationsId"] = "messlokationsId"}, + new Dictionary {["Coverage"] = "Newcoverage"}, + new Dictionary {["Zeitraum.Startdatum"] = "time.startdatum"}, + new Dictionary {["Zeitraum.Enddatum"] = "time.enddatum"} + }; - var multiplicityResult = cr.ToCsv(lineTerminator: Environment.NewLine, reihenfolge: reihenfolge); - Assert.AreEqual(2 + cr.Values.Count, new List(multiplicityResult.Split(Environment.NewLine)).Count); - } + //string JSONdata = "{'completenessZfa':[{'lokationsId':'lokationsId'},{'coverage':'coverage'},{'Zeitraum.einheit':'einheit'},{'Zeitraum.dauer':'dauer'},{'Zeitraum.startdatum':'startdatum'},{'Zeitraum.enddatum':'enddatum'},{'obiskennzahl':'obiskennzahl'},{'einheit':'einheit'},{'wertermittlungsverfahren':'wertermittlungsverfahren'},{'startdatum':'Verbrauch.startdatum'},{'enddatum':'Verbrauch.enddatum'},{'wert':'Verbrauch.wert'},{'headerLine':'1'}]}"; + //var alldata = JsonConvert.DeserializeObject>>>(JSONdata); + //List> reihenfolge = alldata["completenessZfa"]; - [TestMethod] - public void TestDeserialisationCompletenessReportColumnsToCsv() + var newresult = cr.ToCsv(';', true, Environment.NewLine, reihenfolge); + lines = new List(newresult.Split(Environment.NewLine)); + Assert.AreEqual(2, lines.Count); + var decimalSeparator = Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator; + Assert.AreEqual("DE12345;0" + decimalSeparator + "87;2019-01-01T00:00:00Z;2019-03-01T00:00:00Z;", lines[1]); + var commaResult = cr.ToCsv(',', lineTerminator: Environment.NewLine, reihenfolge: reihenfolge); + var separator = ""; + if (decimalSeparator == ",") { - var jsonData = - "{'completenessZfa':[{'lokationsId':'lokationsId'},{'coverage':'coverage'},{'referenceTimeFrame.einheit':'referenceTimeFrame.einheit'},{'referenceTimeFrame.dauer':'referenceTimeFrame.dauer'},{'referenceTimeFrame.startdatum':'referenceTimeFrame.startdatum'},{'referenceTimeFrame.enddatum':'referenceTimeFrame.enddatum'},{'obiskennzahl':'obiskennzahl'},{'einheit':'einheit'},{'wertermittlungsverfahren':'wertermittlungsverfahren'},{'values.startdatum':'Verbrauch.startdatum'},{'values.enddatum':'Verbrauch.enddatum'},{'values.wert':'Verbrauch.wert'},{'headerLine':'1'}]}"; - var reihenfolge = - JsonConvert.DeserializeObject>>>(jsonData); - Assert.AreEqual("coverage", reihenfolge["completenessZfa"][1].Values.First()); + separator = "\""; } - [TestMethod] - public void TestDeserialisationCompletenessReportToCsv() + Assert.AreEqual( + $"DE12345,{separator}0" + decimalSeparator + + $"87{separator},2019-01-01T00:00:00Z,2019-03-01T00:00:00Z,", commaResult.Split(Environment.NewLine)[1]); + var dpunktResult = cr.ToCsv(':', lineTerminator: Environment.NewLine, reihenfolge: reihenfolge); + Assert.AreEqual("DE12345:0" + decimalSeparator + "87:\"2019-01-01T00:00:00Z\":\"2019-03-01T00:00:00Z\":", + dpunktResult.Split(Environment.NewLine)[1]); + + cr.Values = new List { - var jsonData = - "[{\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-09-30T22:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\"},\"_errorMessage\":\"Text of Message\",\"lokationsId\":\"50985149762\",\"obiskennzahl\":\"1-1:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.8402684564,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-27T00:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5000080657\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"},{\"$type\":\"BO4E.Reporting.CompletenessReport, BO4Enet\",\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-09-30T22:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\"},\"_errorMessage\":null,\"lokationsId\":\"DE0004096816100000000000000200712\",\"obiskennzahl\":\"1-1:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.8402684564,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-27T00:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5001065966\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"},{\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\"},\"_errorMessage\":null,\"lokationsId\":\"50985149762\",\"obiskennzahl\":\"1-1:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.3,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-13T00:00:00Z\",\"wert\":null},{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-11-22T00:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5000080657\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"},{\"$type\":\"BO4E.Reporting.CompletenessReport, BO4Enet\",\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\"},\"_errorMessage\":null,\"lokationsId\":\"DE0004096816100000000000000200712\",\"obiskennzahl\":\"1-1:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.3,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-13T00:00:00Z\",\"wert\":null},{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-11-22T00:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5001065966\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"}]"; - var reports = JsonConvert.DeserializeObject>(jsonData); - var lastCsvText = string.Empty; - var counter = 1; - foreach (var report in reports) + new CompletenessReport.BasicVerbrauch + { + Wert = 17, + Startdatum = new DateTimeOffset(2019, 1, 1, 0, 0, 0, TimeSpan.Zero).UtcDateTime, + Enddatum = new DateTimeOffset(2019, 1, 2, 0, 0, 0, TimeSpan.Zero).UtcDateTime + }, + new CompletenessReport.BasicVerbrauch { - lastCsvText += report.ToCsv(';', counter == 1, Environment.NewLine) + Environment.NewLine; - counter++; + Wert = 21, + Startdatum = new DateTimeOffset(2019, 1, 7, 0, 0, 0, TimeSpan.Zero).UtcDateTime, + Enddatum = new DateTimeOffset(2019, 1, 8, 0, 0, 0, TimeSpan.Zero).UtcDateTime + }, + new CompletenessReport.BasicVerbrauch + { + Wert = 35, + Startdatum = new DateTimeOffset(2019, 1, 12, 0, 0, 0, TimeSpan.Zero).UtcDateTime, + Enddatum = new DateTimeOffset(2019, 1, 13, 0, 0, 0, TimeSpan.Zero).UtcDateTime } + }; - Assert.IsTrue(lastCsvText.Length > 0); - } + reihenfolge.Add(new Dictionary { ["Wert"] = "V.wert" }); + reihenfolge.Add(new Dictionary { ["Startdatum"] = "V.startdatum" }); + reihenfolge.Add(new Dictionary { ["Enddatum"] = "V.enddatum" }); - [TestMethod] - public void TestPrivateFieldsAndUserProperties() - { - var jsonData = - "[{\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-09-30T22:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\"},\"_errorMessage\":null,\"lokationsId\":\"50985149762\",\"obiskennzahl\":\"1-1:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.8402684564,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-27T00:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5000080657\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"},{\"$type\":\"BO4E.Reporting.CompletenessReport, BO4Enet\",\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-09-30T22:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\"},\"_errorMessage\":null,\"lokationsId\":\"DE0004096816100000000000000200712\",\"obiskennzahl\":\"1-1:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.8402684564,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-27T00:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5001065966\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"},{\"$type\":\"BO4E.Reporting.CompletenessReport, BO4Enet\",\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\"},\"_errorMessage\":null,\"lokationsId\":\"50985149762\",\"obiskennzahl\":\"1-1:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.3,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-13T00:00:00Z\",\"wert\":null},{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-11-22T00:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5000080657\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"},{\"$type\":\"BO4E.Reporting.CompletenessReport, BO4Enet\",\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\"},\"_errorMessage\":null,\"lokationsId\":\"DE0004096816100000000000000200712\",\"obiskennzahl\":\"1-1:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.3,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-13T00:00:00Z\",\"wert\":null},{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-11-22T00:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5001065966\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"}]"; - var reports = JsonConvert.DeserializeObject>(jsonData); - var lastCsvText = string.Empty; - var counter = 1; - foreach (var report in reports) - { - lastCsvText += report.ToCsv(';', counter == 1, Environment.NewLine) + Environment.NewLine; - counter++; - } + var multiplicityResult = cr.ToCsv(lineTerminator: Environment.NewLine, reihenfolge: reihenfolge); + Assert.AreEqual(2 + cr.Values.Count, new List(multiplicityResult.Split(Environment.NewLine)).Count); + } + + [TestMethod] + public void TestDeserialisationCompletenessReportColumnsToCsv() + { + var jsonData = + "{'completenessZfa':[{'lokationsId':'lokationsId'},{'coverage':'coverage'},{'referenceTimeFrame.einheit':'referenceTimeFrame.einheit'},{'referenceTimeFrame.dauer':'referenceTimeFrame.dauer'},{'referenceTimeFrame.startdatum':'referenceTimeFrame.startdatum'},{'referenceTimeFrame.enddatum':'referenceTimeFrame.enddatum'},{'obiskennzahl':'obiskennzahl'},{'einheit':'einheit'},{'wertermittlungsverfahren':'wertermittlungsverfahren'},{'values.startdatum':'Verbrauch.startdatum'},{'values.enddatum':'Verbrauch.enddatum'},{'values.wert':'Verbrauch.wert'},{'headerLine':'1'}]}"; + var reihenfolge = + JsonConvert.DeserializeObject>>>(jsonData); + Assert.AreEqual("coverage", reihenfolge["completenessZfa"][1].Values.First()); + } - Assert.IsTrue(lastCsvText.Length > 0); - Assert.IsFalse(lastCsvText.Contains(BusinessObject.USER_PROPERTIES_NAME)); - Assert.IsFalse(lastCsvText.Contains("_errorMessage")); + [TestMethod] + public void TestDeserialisationCompletenessReportToCsv() + { + var jsonData = + "[{\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-09-30T22:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\"},\"_errorMessage\":\"Text of Message\",\"lokationsId\":\"50985149762\",\"obiskennzahl\":\"1-1:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.8402684564,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-27T00:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5000080657\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"},{\"$type\":\"BO4E.Reporting.CompletenessReport, BO4Enet\",\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-09-30T22:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\"},\"_errorMessage\":null,\"lokationsId\":\"DE0004096816100000000000000200712\",\"obiskennzahl\":\"1-1:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.8402684564,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-27T00:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5001065966\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"},{\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\"},\"_errorMessage\":null,\"lokationsId\":\"50985149762\",\"obiskennzahl\":\"1-1:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.3,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-13T00:00:00Z\",\"wert\":null},{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-11-22T00:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5000080657\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"},{\"$type\":\"BO4E.Reporting.CompletenessReport, BO4Enet\",\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\"},\"_errorMessage\":null,\"lokationsId\":\"DE0004096816100000000000000200712\",\"obiskennzahl\":\"1-1:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.3,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-13T00:00:00Z\",\"wert\":null},{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-11-22T00:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5001065966\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"}]"; + var reports = JsonConvert.DeserializeObject>(jsonData); + var lastCsvText = string.Empty; + var counter = 1; + foreach (var report in reports) + { + lastCsvText += report.ToCsv(';', counter == 1, Environment.NewLine) + Environment.NewLine; + counter++; } - [TestMethod] - public void TestErrorCsv() + Assert.IsTrue(lastCsvText.Length > 0); + } + + [TestMethod] + public void TestPrivateFieldsAndUserProperties() + { + var jsonData = + "[{\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-09-30T22:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\"},\"_errorMessage\":null,\"lokationsId\":\"50985149762\",\"obiskennzahl\":\"1-1:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.8402684564,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-27T00:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5000080657\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"},{\"$type\":\"BO4E.Reporting.CompletenessReport, BO4Enet\",\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-09-30T22:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\"},\"_errorMessage\":null,\"lokationsId\":\"DE0004096816100000000000000200712\",\"obiskennzahl\":\"1-1:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.8402684564,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-27T00:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5001065966\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"},{\"$type\":\"BO4E.Reporting.CompletenessReport, BO4Enet\",\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\"},\"_errorMessage\":null,\"lokationsId\":\"50985149762\",\"obiskennzahl\":\"1-1:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.3,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-13T00:00:00Z\",\"wert\":null},{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-11-22T00:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5000080657\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"},{\"$type\":\"BO4E.Reporting.CompletenessReport, BO4Enet\",\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\"},\"_errorMessage\":null,\"lokationsId\":\"DE0004096816100000000000000200712\",\"obiskennzahl\":\"1-1:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.3,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-13T00:00:00Z\",\"wert\":null},{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-11-22T00:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5001065966\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"}]"; + var reports = JsonConvert.DeserializeObject>(jsonData); + var lastCsvText = string.Empty; + var counter = 1; + foreach (var report in reports) { - var jsonData = - "{\"boTyp\":\"COMPLETENESSREPORT\",\"versionStruktur\":1,\"obiskennzahl\":\"1-1:5.29.0\",\"values\":[],\"einheit\":\"ZERO\",\"gaps\":null,\"referenceTimeFrame\":{\"einheit\":\"TAG\",\"dauer\":1,\"startdatum\":\"2020-06-30T22:00:00+00:00\",\"enddatum\":\"2020-07-01T22:00:00+00:00\"},\"wertermittlungsverfahren\":\"PROGNOSE\",\"lokationsId\":\"99998888777\",\"coverage\":null,\"profil\":\"000000000123456789\",\"profilRolle\":\"0002\",\"anlagennummer\":\"1234567890\",\"zw\":\"000000000020707999\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"coverage_sum\":0}"; - var report = JsonConvert.DeserializeObject(jsonData); - var csv = report.ToCSV(); - Assert.IsTrue(csv.Contains("99998888777")); + lastCsvText += report.ToCsv(';', counter == 1, Environment.NewLine) + Environment.NewLine; + counter++; } - [TestMethod] - public void TestPrivateFieldsAndUserPropertiesHardCodingCSV() + Assert.IsTrue(lastCsvText.Length > 0); + Assert.IsFalse(lastCsvText.Contains(BusinessObject.USER_PROPERTIES_NAME)); + Assert.IsFalse(lastCsvText.Contains("_errorMessage")); + } + + [TestMethod] + public void TestErrorCsv() + { + var jsonData = + "{\"boTyp\":\"COMPLETENESSREPORT\",\"versionStruktur\":1,\"obiskennzahl\":\"1-1:5.29.0\",\"values\":[],\"einheit\":\"ZERO\",\"gaps\":null,\"referenceTimeFrame\":{\"einheit\":\"TAG\",\"dauer\":1,\"startdatum\":\"2020-06-30T22:00:00+00:00\",\"enddatum\":\"2020-07-01T22:00:00+00:00\"},\"wertermittlungsverfahren\":\"PROGNOSE\",\"lokationsId\":\"99998888777\",\"coverage\":null,\"profil\":\"000000000123456789\",\"profilRolle\":\"0002\",\"anlagennummer\":\"1234567890\",\"zw\":\"000000000020707999\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"coverage_sum\":0}"; + var report = JsonConvert.DeserializeObject(jsonData); + var csv = report.ToCSV(); + Assert.IsTrue(csv.Contains("99998888777")); + } + + [TestMethod] + public void TestPrivateFieldsAndUserPropertiesHardCodingCSV() + { + var jsonData = + "[{\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-09-30T22:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\"},\"_errorMessage\":null,\"lokationsId\":\"50985149762\",\"obiskennzahl\":\"1-65:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.8402684564,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-27T00:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5000080657\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"},{\"$type\":\"BO4E.Reporting.CompletenessReport, BO4Enet\",\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-09-30T22:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\"},\"_errorMessage\":null,\"lokationsId\":\"DE0004096816100000000000000200712\",\"obiskennzahl\":\"1-1:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.8402684564,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-27T00:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5001065966\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"},{\"$type\":\"BO4E.Reporting.CompletenessReport, BO4Enet\",\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\"},\"_errorMessage\":null,\"lokationsId\":\"50985149762\",\"obiskennzahl\":\"1-1:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.3,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-13T00:00:00Z\",\"wert\":null},{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-11-22T00:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5000080657\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"},{\"$type\":\"BO4E.Reporting.CompletenessReport, BO4Enet\",\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\"},\"_errorMessage\":null,\"lokationsId\":\"DE0004096816100000000000000200712\",\"obiskennzahl\":\"1-1:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.3,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-13T00:00:00Z\",\"wert\":null},{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-11-22T00:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5001065966\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"}]"; + var reports = JsonConvert.DeserializeObject>(jsonData); + var lastCsvText = string.Empty; + var counter = 0; + foreach (var report in reports) { - var jsonData = - "[{\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-09-30T22:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\"},\"_errorMessage\":null,\"lokationsId\":\"50985149762\",\"obiskennzahl\":\"1-65:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.8402684564,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-27T00:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5000080657\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"},{\"$type\":\"BO4E.Reporting.CompletenessReport, BO4Enet\",\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-09-30T22:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\"},\"_errorMessage\":null,\"lokationsId\":\"DE0004096816100000000000000200712\",\"obiskennzahl\":\"1-1:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.8402684564,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-27T00:00:00Z\",\"enddatum\":\"2019-10-31T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5001065966\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"},{\"$type\":\"BO4E.Reporting.CompletenessReport, BO4Enet\",\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\"},\"_errorMessage\":null,\"lokationsId\":\"50985149762\",\"obiskennzahl\":\"1-1:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.3,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-13T00:00:00Z\",\"wert\":null},{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-11-22T00:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5000080657\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"},{\"$type\":\"BO4E.Reporting.CompletenessReport, BO4Enet\",\"versionStruktur\":1,\"boTyp\":\"COMPLETENESSREPORT\",\"referenceTimeFrame\":{\"$type\":\"BO4E.COM.Zeitraum, BO4Enet\",\"einheit\":null,\"dauer\":null,\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\"},\"_errorMessage\":null,\"lokationsId\":\"DE0004096816100000000000000200712\",\"obiskennzahl\":\"1-1:1.29.0\",\"einheit\":2000,\"wertermittlungsverfahren\":1,\"coverage\":0.3,\"values\":[],\"gaps\":[{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-10-31T23:00:00Z\",\"enddatum\":\"2019-11-13T00:00:00Z\",\"wert\":null},{\"$type\":\"BO4E.Reporting.CompletenessReport+BasicVerbrauch, BO4Enet\",\"startdatum\":\"2019-11-22T00:00:00Z\",\"enddatum\":\"2019-11-30T23:00:00Z\",\"wert\":null}],\"profil\":\"000000000111127365\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5001065966\",\"zw\":\"000000000020708905\",\"sap_time_zone\":\"CET\",\"sapSanitized\":true,\"valueCount\":0,\"overallGapStart\":\"2019-10-31T23:00:00Z\",\"overallGapEnd\":\"2019-11-30T23:00:00Z\"}]"; - var reports = JsonConvert.DeserializeObject>(jsonData); - var lastCsvText = string.Empty; - var counter = 0; - foreach (var report in reports) + var singleReportLine = report.ToCSV(";", counter == 0, Environment.NewLine) + Environment.NewLine; + if (counter == 0) { - var singleReportLine = report.ToCSV(";", counter == 0, Environment.NewLine) + Environment.NewLine; - if (counter == 0) - { - Assert.IsTrue(singleReportLine.Split(Environment.NewLine)[1] - .StartsWith("2019-09-30T22:00:00Z;2019-10-31T23:00:00Z;;50985149762")); // no melo, just malo - Assert.IsTrue(singleReportLine.Contains("IMS")); - var missingEntries = - ((new DateTime(2019, 10, 31, 23, 0, 0, 0, DateTimeKind.Utc) - - new DateTime(2019, 10, 27, 0, 0, 0, 0, DateTimeKind.Utc)).TotalHours * 4).ToString(); - Assert.IsTrue(singleReportLine.Contains($";{missingEntries};")); - } - else if (counter == 0) // ToDo: where did this come from? - { - Assert.IsTrue(singleReportLine.StartsWith( - "2019-09-30T22:00:00Z;2019-10-31T23:00:00Z;DE0004096816100000000000000200712;;")); // no malo, just melo - Assert.IsTrue(singleReportLine.Contains("RLM")); - } - - lastCsvText += singleReportLine; - counter++; + Assert.IsTrue(singleReportLine.Split(Environment.NewLine)[1] + .StartsWith("2019-09-30T22:00:00Z;2019-10-31T23:00:00Z;;50985149762")); // no melo, just malo + Assert.IsTrue(singleReportLine.Contains("IMS")); + var missingEntries = + ((new DateTime(2019, 10, 31, 23, 0, 0, 0, DateTimeKind.Utc) - + new DateTime(2019, 10, 27, 0, 0, 0, 0, DateTimeKind.Utc)).TotalHours * 4).ToString(); + Assert.IsTrue(singleReportLine.Contains($";{missingEntries};")); + } + else if (counter == 0) // ToDo: where did this come from? + { + Assert.IsTrue(singleReportLine.StartsWith( + "2019-09-30T22:00:00Z;2019-10-31T23:00:00Z;DE0004096816100000000000000200712;;")); // no malo, just melo + Assert.IsTrue(singleReportLine.Contains("RLM")); } - Assert.IsTrue(lastCsvText.Length > 0); - Assert.IsFalse(lastCsvText.Contains(BusinessObject.USER_PROPERTIES_NAME)); - Assert.IsFalse(lastCsvText.Contains("_errorMessage")); + lastCsvText += singleReportLine; + counter++; } + Assert.IsTrue(lastCsvText.Length > 0); + Assert.IsFalse(lastCsvText.Contains(BusinessObject.USER_PROPERTIES_NAME)); + Assert.IsFalse(lastCsvText.Contains("_errorMessage")); + } + - [TestMethod] - public void TestCompletenessReportMitGapToCsv() + [TestMethod] + public void TestCompletenessReportMitGapToCsv() + { + var cr = new CompletenessReport { - var cr = new CompletenessReport - { - LokationsId = "DE12345", - Coverage = 0.87M, // 87% - Wertermittlungsverfahren = Wertermittlungsverfahren.PROGNOSE, - ReferenceTimeFrame = - new Zeitraum - { - Startdatum = new DateTimeOffset(2019, 1, 1, 0, 0, 0, TimeSpan.Zero), - Enddatum = new DateTimeOffset(2019, 3, 1, 0, 0, 0, TimeSpan.Zero) - }, - Values = - new List - { - new CompletenessReport.BasicVerbrauch - { - Wert = 17, - Startdatum = new DateTimeOffset(2019, 1, 1, 0, 0, 0, TimeSpan.Zero).UtcDateTime, - Enddatum = new DateTimeOffset(2019, 1, 2, 0, 0, 0, TimeSpan.Zero).UtcDateTime - }, - new CompletenessReport.BasicVerbrauch - { - Wert = 21, - Startdatum = new DateTimeOffset(2019, 1, 7, 0, 0, 0, TimeSpan.Zero).UtcDateTime, - Enddatum = new DateTimeOffset(2019, 1, 8, 0, 0, 0, TimeSpan.Zero).UtcDateTime - }, - new CompletenessReport.BasicVerbrauch - { - Wert = 35, - Startdatum = new DateTimeOffset(2019, 1, 12, 0, 0, 0, TimeSpan.Zero).UtcDateTime, - Enddatum = new DateTimeOffset(2019, 1, 13, 0, 0, 0, TimeSpan.Zero).UtcDateTime - } - }, - Gaps = new List + LokationsId = "DE12345", + Coverage = 0.87M, // 87% + Wertermittlungsverfahren = Wertermittlungsverfahren.PROGNOSE, + ReferenceTimeFrame = + new Zeitraum + { + Startdatum = new DateTimeOffset(2019, 1, 1, 0, 0, 0, TimeSpan.Zero), + Enddatum = new DateTimeOffset(2019, 3, 1, 0, 0, 0, TimeSpan.Zero) + }, + Values = + new List { new CompletenessReport.BasicVerbrauch { - Wert = 0, - Startdatum = new DateTimeOffset(2017, 1, 1, 0, 0, 0, TimeSpan.Zero).UtcDateTime, - Enddatum = new DateTimeOffset(2017, 1, 2, 0, 0, 0, TimeSpan.Zero).UtcDateTime + Wert = 17, + Startdatum = new DateTimeOffset(2019, 1, 1, 0, 0, 0, TimeSpan.Zero).UtcDateTime, + Enddatum = new DateTimeOffset(2019, 1, 2, 0, 0, 0, TimeSpan.Zero).UtcDateTime }, new CompletenessReport.BasicVerbrauch { - Wert = 0, - Startdatum = new DateTimeOffset(2017, 1, 7, 0, 0, 0, TimeSpan.Zero).UtcDateTime, - Enddatum = new DateTimeOffset(2017, 1, 8, 0, 0, 0, TimeSpan.Zero).UtcDateTime + Wert = 21, + Startdatum = new DateTimeOffset(2019, 1, 7, 0, 0, 0, TimeSpan.Zero).UtcDateTime, + Enddatum = new DateTimeOffset(2019, 1, 8, 0, 0, 0, TimeSpan.Zero).UtcDateTime }, new CompletenessReport.BasicVerbrauch { - Wert = 0, - Startdatum = new DateTimeOffset(2017, 1, 12, 0, 0, 0, TimeSpan.Zero).UtcDateTime, - Enddatum = new DateTimeOffset(2017, 1, 13, 0, 0, 0, TimeSpan.Zero).UtcDateTime + Wert = 35, + Startdatum = new DateTimeOffset(2019, 1, 12, 0, 0, 0, TimeSpan.Zero).UtcDateTime, + Enddatum = new DateTimeOffset(2019, 1, 13, 0, 0, 0, TimeSpan.Zero).UtcDateTime } - } - }; - var multiplicityResult = cr.ToCsv(lineTerminator: Environment.NewLine); - Assert.AreEqual(2 + cr.Values.Count + cr.Gaps.Count, - new List(multiplicityResult.Split(Environment.NewLine)).Count); - } - - [TestMethod] - public void TestCompletenessReportToCsvExceptions() - { - var cr = new CompletenessReport + }, + Gaps = new List { - LokationsId = "DE12345", - Coverage = 0.87M, // 87% - Wertermittlungsverfahren = Wertermittlungsverfahren.PROGNOSE, - ReferenceTimeFrame = new Zeitraum + new CompletenessReport.BasicVerbrauch { - Startdatum = new DateTimeOffset(2019, 1, 1, 0, 0, 0, TimeSpan.Zero), - Enddatum = new DateTimeOffset(2019, 3, 1, 0, 0, 0, TimeSpan.Zero) + Wert = 0, + Startdatum = new DateTimeOffset(2017, 1, 1, 0, 0, 0, TimeSpan.Zero).UtcDateTime, + Enddatum = new DateTimeOffset(2017, 1, 2, 0, 0, 0, TimeSpan.Zero).UtcDateTime + }, + new CompletenessReport.BasicVerbrauch + { + Wert = 0, + Startdatum = new DateTimeOffset(2017, 1, 7, 0, 0, 0, TimeSpan.Zero).UtcDateTime, + Enddatum = new DateTimeOffset(2017, 1, 8, 0, 0, 0, TimeSpan.Zero).UtcDateTime + }, + new CompletenessReport.BasicVerbrauch + { + Wert = 0, + Startdatum = new DateTimeOffset(2017, 1, 12, 0, 0, 0, TimeSpan.Zero).UtcDateTime, + Enddatum = new DateTimeOffset(2017, 1, 13, 0, 0, 0, TimeSpan.Zero).UtcDateTime } - }; + } + }; + var multiplicityResult = cr.ToCsv(lineTerminator: Environment.NewLine); + Assert.AreEqual(2 + cr.Values.Count + cr.Gaps.Count, + new List(multiplicityResult.Split(Environment.NewLine)).Count); + } - // reihenfolge - var reihenfolge = new List> + [TestMethod] + public void TestCompletenessReportToCsvExceptions() + { + var cr = new CompletenessReport + { + LokationsId = "DE12345", + Coverage = 0.87M, // 87% + Wertermittlungsverfahren = Wertermittlungsverfahren.PROGNOSE, + ReferenceTimeFrame = new Zeitraum { - new Dictionary {["LokationsId"] = "messlokationsId"}, - new Dictionary {["Coverage"] = "Newcoverage"}, - new Dictionary {["Zeitraum.Startdatum"] = "time.startdatum"}, - new Dictionary {["Zeitraum.Enddatum"] = "time.enddatum"}, - new Dictionary {["Wert"] = null}, - new Dictionary {["Startdatum"] = "V.startdatum"}, - new Dictionary {["Enddatum"] = "V.enddatum"}, - null - }; - var newResult = string.Empty; - Assert.ThrowsException(() => cr.ToCsv(';', true, Environment.NewLine, reihenfolge)); - Assert.AreEqual(newResult, ""); + Startdatum = new DateTimeOffset(2019, 1, 1, 0, 0, 0, TimeSpan.Zero), + Enddatum = new DateTimeOffset(2019, 3, 1, 0, 0, 0, TimeSpan.Zero) + } + }; + // reihenfolge + var reihenfolge = new List> + { + new Dictionary {["LokationsId"] = "messlokationsId"}, + new Dictionary {["Coverage"] = "Newcoverage"}, + new Dictionary {["Zeitraum.Startdatum"] = "time.startdatum"}, + new Dictionary {["Zeitraum.Enddatum"] = "time.enddatum"}, + new Dictionary {["Wert"] = null}, + new Dictionary {["Startdatum"] = "V.startdatum"}, + new Dictionary {["Enddatum"] = "V.enddatum"}, + null + }; + var newResult = string.Empty; + Assert.ThrowsException(() => cr.ToCsv(';', true, Environment.NewLine, reihenfolge)); + Assert.AreEqual(newResult, ""); - // reihenfolge - var reihenfolge2 = new List> - { - new Dictionary {["lokationsId"] = "messlokationsId"}, - new Dictionary {["coverage"] = "Newcoverage"}, - new Dictionary {["Zeitraum.startdatum"] = "time.startdatum"}, - new Dictionary {["Zeitraum.enddatum"] = "time.enddatum"}, - new Dictionary {["wert"] = "V.wert"}, - new Dictionary {["startdatum"] = "V.startdatum"}, - new Dictionary {["enddatum"] = "V.enddatum"}, - new Dictionary {["asdasd"] = "000"} - }; - Assert.ThrowsException(() => cr.ToCsv(';', true, Environment.NewLine, reihenfolge2)); - Assert.AreEqual(newResult, ""); - } - [TestMethod] - public void TestSerializingCrWithoutGaps() + // reihenfolge + var reihenfolge2 = new List> { - var report = JsonConvert.DeserializeObject( - "{\"_errorMessage\":\"Cannot use autoconfigured method because there are no values.\",\"boTyp\":\"COMPLETENESSREPORT\",\"versionStruktur\":1,\"obiskennzahl\":\"1-1:1.29.0\",\"values\":[],\"einheit\":0,\"gaps\":null,\"referenceTimeFrame\":{ \"einheit\":4,\"dauer\":1.0,\"startdatum\":\"2020-06-30T22:00:00+00:00\",\"enddatum\":\"2020-07-01T22:00:00+00:00\"},\"wertermittlungsverfahren\":0,\"lokationsId\":\"DE000XXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\"coverage\":0.0,\"profil\":\"000000000111129993\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5111111111\",\"zw\":\"000000000020709888\",\"sap_time_zone\":\"CET\",\"sap_profdecimals\":\"06\",\"sapSanitized\":true,\"valueCount\":0,\"coverage_07-01\":0,\"coverage_07-02\":0,\"coverage_07-03\":0,\"coverage_07-04\":0,\"coverage_07-05\":0,\"coverage_07-06\":0,\"coverage_07-07\":0,\"coverage_07-08\":0,\"coverage_07-09\":0,\"coverage_07-10\":0,\"coverage_07-11\":0,\"coverage_07-12\":0,\"coverage_07-13\":0,\"coverage_07-14\":0,\"coverage_07-15\":0,\"coverage_07-16\":0,\"coverage_07-17\":0,\"coverage_07-18\":0,\"coverage_07-19\":0,\"coverage_07-20\":0,\"coverage_07-21\":0,\"coverage_07-22\":0,\"coverage_07-23\":0,\"coverage_07-24\":0,\"coverage_07-25\":0,\"coverage_07-26\":0,\"coverage_07-27\":0,\"coverage_07-28\":0,\"coverage_07-29\":0,\"coverage_07-30\":0,\"coverage_07-31\":0,\"coverage_sum\":0}"); - report.ToCSV(";", true, Environment.NewLine); - } + new Dictionary {["lokationsId"] = "messlokationsId"}, + new Dictionary {["coverage"] = "Newcoverage"}, + new Dictionary {["Zeitraum.startdatum"] = "time.startdatum"}, + new Dictionary {["Zeitraum.enddatum"] = "time.enddatum"}, + new Dictionary {["wert"] = "V.wert"}, + new Dictionary {["startdatum"] = "V.startdatum"}, + new Dictionary {["enddatum"] = "V.enddatum"}, + new Dictionary {["asdasd"] = "000"} + }; + Assert.ThrowsException(() => cr.ToCsv(';', true, Environment.NewLine, reihenfolge2)); + Assert.AreEqual(newResult, ""); + } + + [TestMethod] + public void TestSerializingCrWithoutGaps() + { + var report = JsonConvert.DeserializeObject( + "{\"_errorMessage\":\"Cannot use autoconfigured method because there are no values.\",\"boTyp\":\"COMPLETENESSREPORT\",\"versionStruktur\":1,\"obiskennzahl\":\"1-1:1.29.0\",\"values\":[],\"einheit\":0,\"gaps\":null,\"referenceTimeFrame\":{ \"einheit\":4,\"dauer\":1.0,\"startdatum\":\"2020-06-30T22:00:00+00:00\",\"enddatum\":\"2020-07-01T22:00:00+00:00\"},\"wertermittlungsverfahren\":0,\"lokationsId\":\"DE000XXXXXXXXXXXXXXXXXXXXXXXXXXXX\",\"coverage\":0.0,\"profil\":\"000000000111129993\",\"profilRolle\":\"0001\",\"anlagennummer\":\"5111111111\",\"zw\":\"000000000020709888\",\"sap_time_zone\":\"CET\",\"sap_profdecimals\":\"06\",\"sapSanitized\":true,\"valueCount\":0,\"coverage_07-01\":0,\"coverage_07-02\":0,\"coverage_07-03\":0,\"coverage_07-04\":0,\"coverage_07-05\":0,\"coverage_07-06\":0,\"coverage_07-07\":0,\"coverage_07-08\":0,\"coverage_07-09\":0,\"coverage_07-10\":0,\"coverage_07-11\":0,\"coverage_07-12\":0,\"coverage_07-13\":0,\"coverage_07-14\":0,\"coverage_07-15\":0,\"coverage_07-16\":0,\"coverage_07-17\":0,\"coverage_07-18\":0,\"coverage_07-19\":0,\"coverage_07-20\":0,\"coverage_07-21\":0,\"coverage_07-22\":0,\"coverage_07-23\":0,\"coverage_07-24\":0,\"coverage_07-25\":0,\"coverage_07-26\":0,\"coverage_07-27\":0,\"coverage_07-28\":0,\"coverage_07-29\":0,\"coverage_07-30\":0,\"coverage_07-31\":0,\"coverage_sum\":0}"); + report.ToCSV(";", true, Environment.NewLine); } } \ No newline at end of file