From 52cbe800c1a12c8299c8d4186460ae2b6e1a14e8 Mon Sep 17 00:00:00 2001
From: Michael Krisper <michael.krisper@tugraz.at>
Date: Wed, 13 Jan 2016 16:34:33 +0100
Subject: [PATCH] better validation (also private and protected members, and
 even static members)

---
 .../Simulation/Impl/SimulatorFactory.cs       |  53 +----
 VectoCore/Utils/Validation.cs                 |  17 +-
 VectoCore/VectoCore.csproj                    |   6 +-
 .../SimulationComponentData/ValidationTest.cs | 186 ++++++++++++++++--
 VectoCoreTest/VectoCoreTest.csproj            |   3 +
 5 files changed, 193 insertions(+), 72 deletions(-)

diff --git a/VectoCore/Models/Simulation/Impl/SimulatorFactory.cs b/VectoCore/Models/Simulation/Impl/SimulatorFactory.cs
index 99af792574..1f1ae655a9 100644
--- a/VectoCore/Models/Simulation/Impl/SimulatorFactory.cs
+++ b/VectoCore/Models/Simulation/Impl/SimulatorFactory.cs
@@ -16,6 +16,7 @@
 
 using System.Collections.Generic;
 using System.IO;
+using System.Linq;
 using System.Reflection;
 using System.Security.Principal;
 using System.Threading;
@@ -67,7 +68,6 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 				default:
 					throw new VectoException("Unkown factory mode in SimulatorFactory: {0}", mode);
 			}
-			//DataReader.SetJobFile(jobFile);
 		}
 
 		public IVectoRunDataFactory DataReader { get; private set; }
@@ -89,12 +89,6 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 		{
 			var i = 0;
 			foreach (var data in DataReader.NextRun()) {
-				CheckLossMapRangeForFullLoadCurves(data.GearboxData, data.EngineData, data.AxleGearData);
-
-				//var modFileName = Path.Combine(data.BasePath,
-				//	data.JobName.Replace(Constants.FileExtensions.VectoJobFile, "") + "_{0}{1}" +
-				//	Constants.FileExtensions.ModDataFile);
-				// -> string.Format(modFileName, data.Cycle.Name, data.ModFileSuffix ?? "")
 				var d = data;
 				IModalDataContainer modContainer =
 					new ModalDataContainer(data, ModWriter,
@@ -114,50 +108,17 @@ namespace TUGraz.VectoCore.Models.Simulation.Impl
 				if (data.IsEngineOnly) {
 					run = new TimeRun(builder.Build(data));
 				} else {
-					//var runCaption = string.Format("{0}-{1}-{2}",
-					//	Path.GetFileNameWithoutExtension(data.JobName), data.Cycle.Name, data.ModFileSuffix);
 					run = new DistanceRun(builder.Build(data));
 				}
 
-				yield return run;
-			}
-		}
+				var validationErrors = ValidationHelper.Validate(run);
+				if (validationErrors.Any()) {
+					throw new VectoException("Validation of Run-Data Failed: " +
+											string.Join("; ", validationErrors.Select(r => r.ErrorMessage)));
+				}
 
-		internal static void CheckLossMapRangeForFullLoadCurves(GearboxData gearboxData, CombustionEngineData engineData,
-			AxleGearData axleGearData)
-		{
-			if (gearboxData == null) {
-				return;
-			}
 
-			foreach (var gear in gearboxData.Gears) {
-				for (var angularVelocity = engineData.IdleSpeed;
-					angularVelocity < engineData.FullLoadCurve.RatedSpeed;
-					angularVelocity += 2.0 / 3.0 * (engineData.FullLoadCurve.RatedSpeed - engineData.IdleSpeed) / 10.09) {
-					for (var inTorque = engineData.FullLoadCurve.FullLoadStationaryTorque(angularVelocity) / 3;
-						inTorque < engineData.FullLoadCurve.FullLoadStationaryTorque(angularVelocity);
-						inTorque += 2.0 / 3.0 * engineData.FullLoadCurve.FullLoadStationaryTorque(angularVelocity) / 10.0) {
-						NewtonMeter axleTorque;
-						try {
-							axleTorque = gear.Value.LossMap.GetOutTorque(angularVelocity, inTorque);
-						} catch (VectoException ex) {
-							throw new VectoException(
-								string.Format("Interpolation of Gear-{0}-LossMap failed with torque={1} and angularSpeed={2}",
-									gear.Key, inTorque, angularVelocity.ConvertTo().Rounds.Per.Minute), ex);
-						}
-
-						if (axleGearData != null) {
-							var axleAngularVelocity = angularVelocity / gear.Value.Ratio;
-							try {
-								axleGearData.LossMap.GetOutTorque(axleAngularVelocity, axleTorque);
-							} catch (VectoException ex) {
-								throw new VectoException(
-									string.Format("Interpolation of AxleGear-LossMap failed with torque={0} and angularSpeed={1}",
-										axleTorque, axleAngularVelocity.ConvertTo().Rounds.Per.Minute), ex);
-							}
-						}
-					}
-				}
+				yield return run;
 			}
 		}
 	}
diff --git a/VectoCore/Utils/Validation.cs b/VectoCore/Utils/Validation.cs
index dea997a566..5ceb056f83 100644
--- a/VectoCore/Utils/Validation.cs
+++ b/VectoCore/Utils/Validation.cs
@@ -18,22 +18,26 @@ namespace TUGraz.VectoCore.Utils
 			Validator.TryValidateObject(entity, new ValidationContext(entity), results, true);
 
 			foreach (
-				var p in entity.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic)) {
+				var p in
+					entity.GetType()
+						.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public |
+										BindingFlags.FlattenHierarchy)) {
 				var val = p.GetValue(entity);
 				var attrs = p.GetCustomAttributes(typeof(ValidationAttribute)).Cast<ValidationAttribute>();
-				context.MemberName = p.Name;
 				context.DisplayName = p.Name;
+				context.MemberName = p.Name;
 				Validator.TryValidateValue(val, context, results, attrs);
 			}
 
 			foreach (
 				var f in
 					entity.GetType()
-						.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public)) {
+						.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public |
+									BindingFlags.FlattenHierarchy)) {
 				var val = f.GetValue(entity);
 				var attrs = f.GetCustomAttributes(typeof(ValidationAttribute)).Cast<ValidationAttribute>();
-				context.MemberName = f.Name;
 				context.DisplayName = f.Name;
+				context.MemberName = f.Name;
 				Validator.TryValidateValue(val, context, results, attrs);
 			}
 
@@ -63,7 +67,7 @@ namespace TUGraz.VectoCore.Utils
 					if (results.Any()) {
 						return
 							new ValidationResult(
-								string.Format("Validation for Element {0} in {1} failed: {2}.", i, validationContext.DisplayName,
+								string.Format("Validation for list {1}[{0}] in {1} failed: {2}", i, validationContext.DisplayName,
 									string.Join(" ", results)));
 					}
 					i++;
@@ -72,7 +76,8 @@ namespace TUGraz.VectoCore.Utils
 				var results = value.Validate();
 				if (results.Any()) {
 					return new ValidationResult(
-						string.Format("Validation for {0} failed: {1}.", validationContext.DisplayName, string.Join(" ", results)));
+						string.Format("Validation for object {{{0}}} failed: {1}", validationContext.DisplayName,
+							string.Join(" ", results)));
 				}
 			}
 
diff --git a/VectoCore/VectoCore.csproj b/VectoCore/VectoCore.csproj
index 4d9033dbdb..81706a3d75 100644
--- a/VectoCore/VectoCore.csproj
+++ b/VectoCore/VectoCore.csproj
@@ -94,6 +94,7 @@
       <HintPath>..\packages\NLog.4.2.0\lib\net45\NLog.dll</HintPath>
     </Reference>
     <Reference Include="System" />
+    <Reference Include="System.ComponentModel.DataAnnotations" />
     <Reference Include="System.Core" />
     <Reference Include="System.Drawing" />
     <Reference Include="System.Runtime.Serialization" />
@@ -251,7 +252,9 @@
     <Compile Include="Models\SimulationComponent\IWheels.cs" />
     <Compile Include="Models\SimulationComponent\VectoSimulationComponent.cs" />
     <Compile Include="Models\SimulationComponent\Impl\EngineOnlyDrivingCycle.cs" />
-    <Compile Include="Models\Simulation\Data\ModalResult.cs" />
+    <Compile Include="Models\Simulation\Data\ModalResult.cs">
+      <SubType>Component</SubType>
+    </Compile>
     <Compile Include="Models\Simulation\IVectoRun.cs" />
     <Compile Include="Models\Simulation\Impl\SimulatorFactory.cs" />
     <Compile Include="Models\Simulation\Impl\VectoRun.cs" />
@@ -265,6 +268,7 @@
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Utils\StringExtensionMethods.cs" />
     <Compile Include="Utils\SwitchExtension.cs" />
+    <Compile Include="Utils\Validation.cs" />
     <Compile Include="Utils\VectoCSVFile.cs" />
     <Compile Include="Utils\VectoMath.cs" />
     <Compile Include="Utils\DelauneyMap.cs" />
diff --git a/VectoCoreTest/Models/SimulationComponentData/ValidationTest.cs b/VectoCoreTest/Models/SimulationComponentData/ValidationTest.cs
index e8ab961675..80788fff07 100644
--- a/VectoCoreTest/Models/SimulationComponentData/ValidationTest.cs
+++ b/VectoCoreTest/Models/SimulationComponentData/ValidationTest.cs
@@ -1,11 +1,6 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations;
 using System.Data;
-using System.Diagnostics;
 using System.Linq;
-using System.Reflection;
-using System.Runtime.Serialization;
 using Microsoft.VisualStudio.TestTools.UnitTesting;
 using TUGraz.VectoCore.Models.Simulation.Data;
 using TUGraz.VectoCore.Models.Simulation.Impl;
@@ -89,31 +84,184 @@ namespace TUGraz.VectoCore.Tests.Models.SimulationComponentData
 		[TestMethod]
 		public void Validation_Test()
 		{
-			var data = new Data();
-			data.lu = new deep();
-			var results = data.Validate();
-			Assert.IsFalse(results.Any(), "Validation Failed: " + string.Join(" ", results.Select(r => r.ErrorMessage)));
+			var results = new DataObject().Validate();
+
+			// every field and property should be tested except private parent fields and properties and 
+			// (4*4+1) * 2 = 17*2= 34 - 4 private parent fields (+2 public field and property which are tested twice) = 32
+			Assert.AreEqual(32, results.Count, "Validation Error: " + string.Join("\n", results.Select(r => r.ErrorMessage)));
 		}
 
 
-		public class deep
+		public class DeepDataObject
 		{
-			[Required, Range(10, 16)] public int mah = 45;
+			[Required, Range(41, 42)] protected int public_field = 5;
 		}
 
 
-		public abstract class Muh
+		public abstract class ParentDataObject
 		{
-			[Required, Range(6, 9)]
-			protected int higss { get; set; }
+			#region 4 parent instance fields
 
-			[Required, ValidateObject] public deep lu;
-		}
+			[Required, Range(1, 2)] private int private_parent_field = 7;
+			[Required, Range(3, 4)] protected int protected_parent_field = 7;
+			[Required, Range(5, 6)] internal int internal_parent_field = 7;
+			[Required, Range(7, 8)] public int public_parent_field = 5;
+
+			#endregion
+
+			#region 4 parent static field
+
+			[Required, Range(43, 44)] private static int private_static_parent_field = 7;
+			[Required, Range(43, 44)] protected static int protected_static_parent_field = 7;
+			[Required, Range(50, 51)] internal static int internal_static_parent_field = 7;
+			[Required, Range(45, 46)] public static int public_static_parent_field = 7;
+
+			#endregion
+
+			#region 4 parent instance properties
+
+			[Required, Range(11, 12)]
+			private int private_parent_property
+			{
+				get { return 7; }
+			}
+
+			[Required, Range(13, 14)]
+			protected int protected_parent_property
+			{
+				get { return 7; }
+			}
+
+			[Required, Range(15, 16)]
+			internal int internal_parent_property
+			{
+				get { return 7; }
+			}
+
+			[Required, Range(17, 18)]
+			public int public_parent_property
+			{
+				get { return 7; }
+			}
+
+			#endregion
+
+			#region 4 parent static properties
+
+			[Required, Range(19, 20)]
+			private static int private_static_parent_property
+			{
+				get { return 7; }
+			}
+
+			[Required, Range(19, 20)]
+			protected static int protected_static_parent_property
+			{
+				get { return 7; }
+			}
+
+			[Required, Range(19, 20)]
+			internal static int internal_static_parent_property
+			{
+				get { return 7; }
+			}
+
+			[Required, Range(19, 20)]
+			public static int public_static_parent_property
+			{
+				get { return 7; }
+			}
+
+			#endregion
+
+			#region 1 parent sub objects
+
+			[Required, ValidateObject] public DeepDataObject parent_sub_object = new DeepDataObject();
 
+			#endregion
+		}
 
-		public class Data : Muh
+		public class DataObject : ParentDataObject
 		{
-			[Required, Range(2, 5)] private int bla = 7;
+			#region 4 instance fields
+
+			[Required, Range(1, 2)] private int private_field = 7;
+			[Required, Range(3, 4)] protected int protected_field = 7;
+			[Required, Range(5, 6)] internal int internal_field = 7;
+			[Required, Range(7, 8)] public int public_field = 5;
+
+			#endregion
+
+			#region 4 static field
+
+			[Required, Range(43, 44)] private static int private_static_field = 7;
+			[Required, Range(43, 44)] protected static int protected_static_field = 7;
+			[Required, Range(50, 51)] internal static int internal_static_field = 7;
+			[Required, Range(45, 46)] public static int public_static_field = 7;
+
+			#endregion
+
+			#region 4 instance properties
+
+			[Required, Range(11, 12)]
+			private int private_property
+			{
+				get { return 7; }
+			}
+
+			[Required, Range(13, 14)]
+			protected int protected_property
+			{
+				get { return 7; }
+			}
+
+			[Required, Range(15, 16)]
+			internal int internal_property
+			{
+				get { return 7; }
+			}
+
+			[Required, Range(17, 18)]
+			public int public_property
+			{
+				get { return 7; }
+			}
+
+			#endregion
+
+			#region 4 static properties
+
+			[Required, Range(19, 20)]
+			private static int private_static_property
+			{
+				get { return 7; }
+			}
+
+			[Required, Range(19, 20)]
+			protected static int protected_static_property
+			{
+				get { return 7; }
+			}
+
+			[Required, Range(19, 20)]
+			internal static int internal_static_property
+			{
+				get { return 7; }
+			}
+
+			[Required, Range(19, 20)]
+			public static int public_static_property
+			{
+				get { return 7; }
+			}
+
+			#endregion
+
+			#region 1 sub objects
+
+			[Required, ValidateObject] public DeepDataObject sub_object = new DeepDataObject();
+
+			#endregion
 		}
 	}
 }
\ No newline at end of file
diff --git a/VectoCoreTest/VectoCoreTest.csproj b/VectoCoreTest/VectoCoreTest.csproj
index b651c3762c..6da7ec8584 100644
--- a/VectoCoreTest/VectoCoreTest.csproj
+++ b/VectoCoreTest/VectoCoreTest.csproj
@@ -44,10 +44,12 @@
       <HintPath>..\packages\NLog.4.0.1\lib\net45\NLog.dll</HintPath>
     </Reference>
     <Reference Include="System" />
+    <Reference Include="System.ComponentModel.DataAnnotations" />
     <Reference Include="System.Data" />
     <Reference Include="System.Data.DataSetExtensions" />
     <Reference Include="System.Design" />
     <Reference Include="System.Drawing" />
+    <Reference Include="System.Runtime.Serialization" />
     <Reference Include="System.Windows.Forms" />
     <Reference Include="System.Windows.Forms.DataVisualization" />
     <Reference Include="System.Xml" />
@@ -76,6 +78,7 @@
       <SubType>Code</SubType>
     </Compile>
     <Compile Include="Integration\DeclarationReportTest.cs" />
+    <Compile Include="Models\SimulationComponentData\ValidationTest.cs" />
     <Compile Include="Models\Simulation\FactoryTest.cs" />
     <Compile Include="Models\Simulation\LossMapRangeValidationTest.cs" />
     <Compile Include="Reports\SumWriterTest.cs" />
-- 
GitLab